SMLNJ - Function works by itself, but not within another function - sml

I have this function:
addBinaryTreeNode((genRandomNumber(100), genRandomNumber(100), genRandomNumber(100)), tree, 1, [])
That returns a data type "binaryTree". It will compile when that is by itself, but when I have it in a function:
generate3DNodeTree(addBinaryTreeNode((genRandomNumber(100), genRandomNumber(100), genRandomNumber(100)), tree, 1, []), numToGen - 1)
...it will not compile, giving me these errors:
stdIn:215.21-215.135 Error: operator and operand don't agree [tycon mismatch]
operator domain: (int * int * int) * binaryTree * int * int list
operand: ((Random.rand -> int) * (Random.rand -> int) * (Random.rand -> int)) * binaryTree * [int ty] * 'Z list
in expression:addBinaryTreeNode((genRandomNumber 100,genRandomNumber 100,genRandomNumber 100),tree,1,nil)
The function "generate3DNodeTree" has arguments:
(tree : binaryTree, numToGen : int)
...which are exactly what I'm passing to it. Why doesn't this work?
generate3DNodeTree works if I pass it like so:
generate3DNodeTree(tree, numToGen - 1)
SMLNJ knows that the return type of addBinaryTreeNode is binaryTree, so I don't know what the issue could be.

The problem is that your genRandomNumber doesn't return an int. Instead it returns a function of type Random.rand -> int, where Random.rand is the type of a random number generator. You could change the definition of genRandomNumber so that it evaluates this function at a generator and returns an int.
According to the documentation of the Random structure, the function Random.rand(i,j) creates such a generator. In production code you would want to find a way to seed it from the system clock (which doesn't seem easy in SML) though for testing purposes you can just hard-wire in a specific i and j:
val generator = Random.rand(1,5)
fun genRandomNumber(numToGen) = Random.randRange(1, numToGen) generator;
Using these definitions, genRandomNumber is now a function of type int -> int, hence using this definition you won't have the same type mismatch error.

Related

Ocaml: How to define function with specific type

I know this could be stupid question, but since I'm new to Ocaml, please give me some tips on defining functions with specific type.
I want to define function which type has int * int * (int -> int) -> int
So I made a function like this.
let rec sigma a b func:int->int=
if a >= b then func(a)
else func(a) + sigma(a+1, b, func)
But sigma function here does not have type int * int * (int->int) -> int. Instead its type is int->int->(int->int)->int.
How should I define function sigma to have type int * int * (int->int) -> int?
(Error Message :
Error: This expression has type 'a * 'b * 'c
but an expression was expected of type int
The type int * int * (int->int) -> int denotes a function that takes a 3-tuple and returns and integer. A tuple (pair, triple, quadruple, etc) is written as (a,b,c,...), e.g.,
let rec sigma (a,b,func) : int =
if a >= b then func(a)
else func(a) + sigma(a+1, b, func)
With all that said, it is usually a bad idea to pass arguments via tuples in OCaml. It hampers currying, inefficient (each tuple is boxed into a separate value), and in general non-functional and not nice.
Also, when you constrain a parameter of a function, you shall parenthesize it, e.g., (func : int -> int).
And normally functions in OCaml are applied by juxtaposition of a function name and its arguments, e.g., given a function add
let add x y = x + y
we can apply (call it) just as add 3 5 (not add(3,5)!)
Therefore, the conventional way to define your sigma function would be
let rec sigma a b func : int =
if a >= b then func a
else func a + sigma (a+1) b func

SML Error: operator and operand don't agree [tycon mismatch]

I'm new to SML and don't quite understand my issue, although I'm certain I'm at fault. First off, here are two short functions I am testing and their descriptions.
MakeInterval - Takes a natural number r, (also used for rp) and a natural number t, and returns the interval [t-r,t+r].
fun MakeInterval(r,rp,t) =
if r + rp < 0 then []
else t-r :: MakeInterval(r-1,rp,t);
E.g. MakeInterval(3,3,10) will return [7,8,9,10,11,12,13]. If you have a suggestion for getting rid of rp, please let me know. It's the only way I could think of to keep track of the original value of r while maintaining sorted order.
NotDivisible - Takes a natural number r, a list of natural numbers ts1 and another list of natural numbers ts2. Code using ts2 isn't yet written.
r specifies the lower and upper bounds of the interval, (same as MakeInterval), and ts1 is a list of numbers to be fed into map with the MakeInterval function.
fun NotDivisible(r, ts1, ts2) =
map (fn x => MakeInterval(r,r,x), ts1);
This function should return a list of intervals. E.g. NotDivisible(3, [10,20,30],
[2,4,6]) will return (for now) [[7..13], [17..23], [27..33]].
After I get this working, I will begin manipulating these lists to find which numbers out of these intervals are indivisible by any of the numbers in ts2.
But for now, my issue lies with the function definitions as I have them. MakeInterval is defined with no issues and I have tested it on it's own. This is the error I receive when attempting to define NotDivisible:
stdIn:5.33-5.71 Error: operator and operand don't agree [tycon mismatch]
operator domain: 'Z -> 'Y
operand: (int -> int list) * 'X
in expression:
map ((fn x => MakeInterval <exp>),ts1)
I've tried specifying all types manually to no avail. Everything makes sense to me logically, but clearly there is a syntax issue here that I am not following.
The issue with the above is the invocation of map, the function is curried
map : ('a -> 'b) -> 'a list -> 'b list;
so, a small change to the parentheses:
fun NotDivisible(r, ts1, ts2) = map (fn x => MakeInterval(r,r,x)) ts1;
gives you:
val NotDivisible = fn : int * int list * 'a -> int list list

operator and operand don't agree [tycon mismatch] - sml assuming the wrong list type

I have a pretty simple code that's supposed to transform a list of tuples (int * string), into two lists, one list of ints and one list of strings - basically a list of tuples into a tuple of lists.
fun unzip_single_int[] : int list = []
| unzip_single_int(x::xs) : int list =
x :: unzip_single_int(xs)
fun unzip_single_string[] : string list = []
| unzip_single_string(x::xs) : string list =
x :: unzip_single_string(xs)
fun unzip[] : (int list * string list) = ([], [])
| unzip([twopls]) : (int list * string list) =
let
val x : int list = unzip_single_int(twopls);
val y : string list = unzip_single_string(twopls); (* this is line 28 btw *)
in
(x, y)
end
And the error:
zip.sml:28.7-28.52 Error: operator and operand don't agree [tycon mismatch]
operator domain: string list
operand: int list
in expression:
unzip_single_int twopls
For some reason the compiler believes val y : string list = unzip_single_string(twopls) is referring to an int list.
Interestingly enough, when I switch the two around, when I change:
val x : int list = unzip_single_int(twopls);
val y : string list = unzip_single_string(twopls);
to
val y : string list = unzip_single_string(twopls);
val x : int list = unzip_single_int(twopls);
The error switches too:
zip.sml:28.7-28.47 Error: operator and operand don't agree [tycon mismatch]
operator domain: int list
operand: string list
in expression:
unzip_single_int twopls
For some reason, whatever the second call is, it's going to assume that its whatever the last call's type was. Why is it doing this? How do I overcome this? I made it very clear in the two other functions definitions that they are int lists and string lists respectively, so why does SML think that I'm sending it a string list when I clearly defined it as an int list ?
Thanks!
The answer to your question is type inference. You haven't given any type for twopls or an argument type for unzip, and you are calling unzip_single_int(twopls) when you make a value declaration for x. Therefore, SML infers that twopls is an int list, because the type of your function unzip_single_int is int list -> int list, which means it takes an int list as input and returns an int list.
After SML infers that twopls is an int list, you are trying to call unzip_single_string(twopls). However, the type of the function unzip_single_string is string list -> string list, therefore it expects an expression of string list as an input. But now twopls is an int list, so you get a type error.
However, your function definitions don't change anything about the list, they return the exact same list, I'm guessing you want them to return either the first or the second element in the tuple, so you should add that. Your unzip function is supposed to have the type (int * string) list -> int list * string list. Therefore, try to pattern match on the int * string elements you have in your list. Normally you would pattern match a list like x :: xs, but if you know the elements are tuples and if you want to access them, you can pattern match them like (num, str) :: xs, where num is an int variable and str is a string variable. You should be able to figure out the rest. Good luck!

SML function type

I have a hard time understanding the Type of a certain SML function i need to create.
It is a helper function that should return the longest string from a list of strings.
The type should be: (int * int -> bool) -> string list -> string
How should i read this and how can i create a function that would match?
I started by following simple code:
fun helper(x,y)=x>y
But now i should have this method to return a string list and then a string. But i seem to be missing some points here.
This is the signature of a curried function: (int * int -> bool) -> string list -> string
(int * int -> bool): this is the first argument, and it is a function that receives a tuple of two integers and returns a boolean. Looks like a predicate function.
string list: this is the second argument, a list of strings
string: and this is the resulting type of your function.
For instance, in the course of Programming Languages (which appears to be the source of the question) the function in question should look somewhat like:
fun longest_string_helper f xs = ...
Where
f is a function value of type (int * int -> bool)
xs is a list value of type string list
And of course the function returns a string value.
Notice that the arguments in the function declaration are separated by spaces, and not within a tuple pattern. That evidences that this is a curried function. You can read about this in the course reading notes for section 3, under Another Closure Idiom: Currying and Partial Application (page 11).

SML - operator and operand disagree

I have this simple function:
val CLC_seq=
fn (n) =>
(Cons (n, find_CLC_seq(COL_seq(n))))
When:
find_CLC_sqe is : int seq -> int;
COL_seq is: fn: int -> int seq;
The complier wrote:
Error: operator and operand don't agree
operator domain: int * (Unit -> int seq)
operand: int * int
in expression:
(Cons (n, find_CLC_seq(COL_seq(n))))
What is the reason? How can I solve it? Thank you.
Well, it's not clear what you're trying to do exactly, but the compiler is right to pick you up on it. find_CLC_seq returns an int, which means your Cons is trying to cons an int onto an int. That makes no sense, because cons is for adding an element to the front of a list (your Cons function is expecting to put an int on the front of a lazy sequence, a (Unit -> int seq)).
I don't know what CLC and COL are, but it looks like either:
Your definition of CLC_seq is wrong, because if find_CLC_seq is really meant to return an int, it doesn't make sense to be using it that way;
OR your definition of find_CLC_seq is wrong, and its return type should be int seq or a lazy sequence, as the name implies. In that case, the error is in a bit of code you haven't shown us.