SML: Implementing Multiply with Restrictions - recursion

I'm trying to implement multiply in SML with a few restrictions. I'm given the following add function:
fun add (0 : int, m : int) : int = m
| add (n : int, m : int) : int = 1 + add(n-1, m)
I'm trying to write a function such that mult (m, n) recursively calculates the product of m and n, for any two natural numbers m and n. Your implementation may use the function add mentioned above and - (subtraction), but it may not use + or *.
Here's my attempt:
fun multiply(0 : int, m : int) = 0
| multiply(n : int, 0 : int) = 0
| multiply(1 : int, m : int) = m
| multiply(n : int, 1 : int) = n
| multiply(~1 : int, m : int) = ~m
| multiply(n : int, ~1 : int) = ~n
| multiply(n : int, m : int) =
if (n > 0 andalso m > 0) then
add(add(0, n), multiply(n, m - 1))
else
if (n < 0 andalso m < 0) then
multiply(~n, ~m)
else
if (n < 0 andalso m > 0) then
n - multiply(n, m - 1)
(* n > 0 and m < 0 *)
else
m - multiply(m, n - 1);
It works when n and m are both positive or both negative but not when one is positive and the other negative but I can't seem to figure out my bug. For instance,
multiply(3, ~10) evaluates to 0. So I think my recursive call is getting to 0 and causing it to evaluate to 0. Having said that, my base cases take care of this so I'm not sure how it'd be possible.
Ideas?

Change the m - multiply(m, n - 1); to m - multiply(~m, n - 1);. (and the same for the other n -... line) The way you have it, you're subtracting a negative number from itself, so you're effectively canceling it out, and triggering a base case of 0.
Trace:
= multiply (3, -10)
= -10 - multiply (2, -10)
= -10 - (-10) - multiply (1, -10)
= -10 - (-10) - (-10)
As soon as there's a (-10) - (-10) you're setting off multiply(0 : int, m : int) which results in the 0, so your intuition about it being triggered was correct.
I realized you can't use +, so here's code that follows that. Becaase you need to multiply, we keep the basic logic the same, but instead of recursing with the same numbers, we turn the negative number positive before passing it to the recursive call.
fun multiply(0 : int, m : int) = 0
| multiply(n : int, 0 : int) = 0
| multiply(1 : int, m : int) = m
| multiply(n : int, 1 : int) = n
| multiply(~1 : int, m : int) = ~m
| multiply(n : int, ~1 : int) = ~n
| multiply(n : int, m : int) =
if (n > 0 andalso m > 0) then
add(add(0, n), multiply(n, m - 1))
else if (n < 0 andalso m < 0) then
multiply(~n, ~m)
else if (n < 0 andalso m > 0) then
n - multiply(~n, m - 1)
else (* n > 0 and m < 0 *)
m - multiply(n - 1, ~m);
Also, a minor nitpick, but you can change add(add(0, n), multiply(n, m - 1)) to add(n, multiply(n, m - 1))

Related

Is there any way to optimize this function and make it faster?

is there a way to optimize this? It is taking way too long to run
let counter2 = ref 0
let rec s2 num =
counter2 := !counter2 + 1;
match num with
| 0 -> 1
| 1 -> 2
| _ -> (((((6*num)-3) * (s2 (num-1))) / (num+1))) - (((num-2)* (s2 (num-2))/(num+1)))
Here is the highly recursive definition of the Fibonacci sequence:
let rec fib n =
if n < 2 then n
else fib (n - 2) + fib (n - 1)
Here is the not so recursive definition of the Fibonacci sequence.
let nfib n =
let rec helper pprev prev i =
if i = n then
pprev + prev
else
helper prev (pprev + prev) (i + 1)
in
if n < 2 then n
else helper 0 1 2
Here is a function for timing things:
let time f x =
let st = Unix.gettimeofday () in
let res = f x in
Printf.printf "%f seconds\n" (Unix.gettimeofday () -. st);
res
Here are times for the fib and nfib functions:
# time fib 42;;
7.694294 seconds
- : int = 267914296
# time nfib 42;;
0.000002 seconds
- : int = 267914296

Why is it giving me this error? This expression has type Z.t but an expression was expected of type int

EDITED: Alright, this is the complete error :
45 | | _ -> Z.of_int 3 * Z.(s1 (num-1)) + Z.(sum_s1 num)
^^^^^^^^^^
Error: This expression has type Z.t but an expression was expected of type
int
And this is the code in question :
let rec s1 num =
match num with
| 0 -> Z.of_int(1)
| 1 -> Z.of_int(2)
| _ -> Z.of_int 3 * Z.(s1 (num-1)) + Z.(sum_s1 num)
and
sum_s1 num =
let rec sum_s1_impl (num, k) =
if (num-2 < 1) || (k > num-2) then 0
else (s1 k) * (s1 (num-k-1)) + (sum_s1_impl (num, k+1))
in sum_s1_impl (num, 1);;
I don't know where is the problem/how can I fix it (some tips)
Thanks!!
EDIT#2 :
let rec s1 num =
match num with
| 0 -> Z.of_int(1)
| 1 -> Z.of_int(2)
| _ -> Z.of_int(3 * (s1 (num-1)) + (sum_s1 num))
and
sum_s1 num =
let rec sum_s1_impl (num, k) =
if (num-2 < 1) || (k > num-2) then 0
else (s1 k) * (s1 (num-k-1)) + (sum_s1_impl (num, k+1))
in sum_s1_impl (num, 1);;
Even with the use of Z.of_int(3 * (s1 (num-1)) + (sum_s1 num))
I stil get the same error
Generally speaking you need to carefully track which of your parameters are of type int (ordinary OCaml integer) and which are Z.t (big integer). You seem to treat them as if they're the same type, which doesn't work in a strongly typed language.
The first reported error is for this expression:
Z.of_int 3 * Z.(s1 (num-1)) + Z.(sum_s1 num)
If I look at the code for s1 it shows that it expects an int parameter, since it matches the parameter against 0, 1, etc. Similarly, the code for sum_s1 expects an int parameter since it applies the built-in - operator to the parameter.
With these assumptions, the first problem in this expression is that Z.of_int returns a big integer (Z.t). You can't multiply a big integer using the built-in * operator.
But note that this subexpression looks wrong also:
Z.(s1 (num - 1))
Since the expression is prefixed with Z., the operators will come from the Z module. Hence the - is of type Z.t -> Z.t -> Z.t. But you're applying it to num and 1 which are ordinary OCaml ints.
You need to go through the expressions and figure out the type you want for each subpart. Generally you want to do everything using big integers, so you should convert using Z.of_int whenever you have a regular OCaml int. Most of the parameters and return values of your functions should (in my opinion) be big integers.
You are multiplying non int type Z.of_int 3 by an int (* operator).
Try to do your operations with ints, and then convert the end result to Z.of_int (your result)
EDIT : Also, you can use built-in zerith operators, ie :
val add : t -> t -> t
Addition.
Check https://www-apr.lip6.fr/~mine/enseignement/l3/2015-2016/doc-zarith/Z.html

Reversing an int in OCaml

I'm teaching myself OCaml, and the main resources I'm using for practice are some problem sets Cornell has made available from their 3110 class. One of the problems is to write a function to reverse an int (i.e: 1234 -> 4321, -1234 -> -4321, 2 -> 2, -10 -> -1 etc).
I have a working solution, but I'm concerned that it isn't exactly idiomatic OCaml:
let rev_int (i : int) : int =
let rec power cnt value =
if value / 10 = 0 then cnt
else power (10 * cnt) (value/10) in
let rec aux pow temp value =
if value <> 0 then aux (pow/10) (temp + (value mod 10 * pow)) (value / 10)
else temp in
aux (power 1 i) 0 i
It works properly in all cases as far as I can tell, but it just seems seriously "un-OCaml" to me, particularly because I'm running through the length of the int twice with two inner-functions. So I'm just wondering whether there's a more "OCaml" way to do this.
I would say, that the following is idiomatic enough.
(* [rev x] returns such value [y] that its decimal representation
is a reverse of decimal representation of [x], e.g.,
[rev 12345 = 54321] *)
let rev n =
let rec loop acc n =
if n = 0 then acc
else loop (acc * 10 + n mod 10) (n / 10) in
loop 0 n
But as Jeffrey said in a comment, your solution is quite idiomatic, although not the nicest one.
Btw, my own style, would be to write like this:
let rev n =
let rec loop acc = function
| 0 -> acc
| n -> loop (acc * 10 + n mod 10) (n / 10) in
loop 0 n
As I prefer pattern matching to if/then/else. But this is a matter of mine personal taste.
I can propose you some way of doing it:
let decompose_int i =
let r = i / 10 in
i - (r * 10) , r
This function allows me to decompose the integer as if I had a list.
For instance 1234 is decomposed into 4 and 123.
Then we reverse it.
let rec rev_int i = match decompose_int i with
| x , 0 -> 10 , x
| h , t ->
let (m,r) = rev_int t in
(10 * m, h * m + r)
The idea here is to return 10, 100, 1000... and so on to know where to place the last digit.
What I wanted to do here is to treat them as I would treat lists, decompose_int being a List.hd and List.tl equivalent.

Why ocamlc says I mismatched {} while I don't?

I have written myPercolation.ml.
open MyUnionFind
module type MyPercolationSig = sig
type percolation
val create_percolation : int -> percolation
val open_site : percolation -> int -> int -> unit
val is_open : percolation -> int -> int -> bool
val is_full : percolation -> int -> int -> bool
val can_percolates : percolation -> bool
end
module MyPercolation : MyPercolationSig = struct
exception IndexOutOfBounds;;
type percolation =
{n : int;
sites: bool array;
union : MyUnionFind.union_find};;
let create_percolation n =
{n = n; sites = Array.make (n*n) false; union = MyUnionFind.create_union (n*n)};;
let open_site p i j =
let {n;_;union} = p
in
if not (is_open p i j) then
begin
sites.(index_of n i j) <- true;
if i - 1 >= 1 && i - 1 <= n && is_open n (i-1) j then
MyUnionFind.union union (index_of n i j) (index_of n (i-1) j)
else if i + 1 >= 1 && i + 1 <= n && is_open n (i+1) j then
MyUnionFind.union union (index_of n i j) (index_of n (i+1) j)
else if j - 1 >= 1 && j - 1 <= n && is_open n i (j-1) then
MyUnionFind.union union (index_of n i j) (index_of n i (j-1))
else if j + 1 >= 1 && j + 1 <= n && is_open n i (j+1) then
MyUnionFind.union union (index_of n i j) (index_of n i (j+1))
end;;
let index_of n i j = n * (i - 1) + j;;
let is_open {n;sites;_} i j =
if i < 1 || i > n || j < 1 || j > n then
raise IndexOutOfBounds
else
sites.(index_of n i j);;
let is_full {n;_;union} i j =
let rec is_connected_top j' =
if j = 0 then false
else
if MyUnionFind.is_connected union (index_of n i j) (index_of n 0 j') then true
else is_connected_top (j'-1)
in is_connected_top n;;
let can_percolates p =
let {n;_;_} = p
in
let rec is_full_bottom j =
if j = 0 then false
else
if is_full p n j then true
else is_full_bottom (j-1)
end
Please ignore the package MyUnionFind package. It is just a homemade implementation for union-find algorithm.
when I try to compile the myPercolation.ml, I got such an error:
$ ocamlc -c myPercolation.ml
File "myPercolation.ml", line 25, characters 11-12:
Error: Syntax error: '}' expected
File "myPercolation.ml", line 25, characters 8-9:
Error: This '{' might be unmatched
I think the error is talking about let {n;_;union} = p in function of let open_site p i j.
I have read through that line and all code many times, but I still don't see any mismatched {} in that line.
can anyone help please?
Another possible error: {n;_;_} should be {n;_} Only 1 underscore is necessary. Think of it like the _ wildcard in a match statement.
The expression let {n; _; union} = p is not well formed OCaml. I think what you want is let {n; union} = p. The way to handle fields you don't care about in a record pattern is not to mention them.
Update:
As rgrinberg points out, a much better way to describe the problem is that the _ has to appear as the last field. That's why the compiler is expecting to see } afterward. It might be good style to include the _ as an indicator that you're purposely matching only a subset of the fields of the record. You can, in fact, turn on a compiler option that checks for this.
Update 2:
The warning for incomplete record patterns is warning number 9, and also is associated with the letter R. Here's how to use R:
$ ocaml -w +R
OCaml version 4.00.0
# type r = { a: int; b: char };;
type r = { a : int; b : char; }
# let {a} = {a=3; b='x'} in a;;
Warning 9: the following labels are not bound in this record pattern:
b
Either bind these labels explicitly or add '; _' to the pattern.
- : int = 3
The command-line syntax is the same for the compiler.

Using Greatest Common Divisor fun

euclid :: Int -> Int
euclid n = length (filter (gcd n == 1) [1 .. n-1])
gcd :: Int -> Int -> Int
..
Your error comes from "gcd x 0 = x". The "x :: Int" is the inferred result but the type declaration of "gcd :: Int->Int->Bool" expects Bool. I expect that "gcd x 0 = (x==1)" is what you ought to have typed.
Assuming you're looking for Euler's totient function, simply call
euler_fi1 n = length $ filter ((==1).(gcd n)) [1..n-1]
The linked WP article gives a formula for calculating this directly:
euler_fi n = let
fs = Data.List.nub $ factorize n
pr = n * product [p-1 | p <- fs]
in Data.List.foldl' div pr fs
You'll need a factorize function for that:
factorize n | n > 1 = go n (2:[3,5..]) where
go n ds#(d:t)
| d*d > n = [n]
| r == 0 = d : go q ds
| otherwise = go n t
where
(q,r) = quotRem n d
Next optimization is to use primes list instead of (2:[3,5..]).

Resources