Search code examples
smlsmlnj

How to make a randomly populated list recursively in SML/NJ


fun randomList(n) =  let 
    val theList = []
    val min = 1
    val max = 75
    val nextInt = Random.randRange(min,max)
    val r = Random.rand(1,1)
    val randomValue = nextInt r
    in  
    if n = 0 then [] 
    else 
    (randomValue::theList;
    randomList(n-1)) end;

randomList(50); 

I'm trying to populate a list with random numbers. I'm getting the error Warning: type vars not generalized because of value restriction are instantiated to dummy types (X1, X2,...) I've seen some different possible reasons for this but I can't figure it out. What do I need to change? I'm still not sure that the function even works because I haven't been able to fully run it.


Solution

  • The function which you give is giving the type:

    val randomList = fn : int -> 'a list
    

    So ask, why then is 'a not generalizing to int? Lets look at the expression in the else branch.

    - val foo = ({}; 5);
    val foo = 5 : int
    

    The expression (e1; e2) evaluates e1, and then evaluates and returns e2, Throwing away the result of e1. From there, it should start to make sense why it is returning an 'a list.

    1. Move theList to a parameter.
    2. Add a helper function passing the empty list, to it.
    3. Returning theList after it has accumulated all the random numbers.
    4. As you noted in the comments it helps to pull the random seed r to an argument of the helper function, so the random number generator doesn't generate keep generating the same number.

      we still use the same initial seed for every call of randomList so each call of the same length will return the same list. a better seed function can be found here: Seeding Sml/NJ RNG

    fun randomList (n) =
     let fun helper (n, s) theList =
      if n = 0
         then theList
         else
          let val min = 1
              val max = 75
              val nextInt = Random.randRange(min,max)
              val randomValue = nextInt s
           in helper (n - 1, s) (randomValue::theList)
          end;
     in helper (n, Random.rand(1, 1)) [] end;