Search code examples
smlsmlnj

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


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.


Solution

  • 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.