Search code examples
recursionsmlsmlnj

How to recursively make a list of lists in SML/NJ


I'm brand new to SML/NJ and I'm trying to make a recursive function that makes a listOfLists. Ex: listOf([1,2,3,4]) will output [[1],[2],[3],[4]]. I've found a recursive merge in SML/NJ, and I'm trying to use it as kind've an outline:

- fun merge(xs,nil) = xs
= | merge(nil,ys) = ys
= | merge(x::xs, y::ys) =
= if (x < y) then x::merge(xs, y::ys) else y::merge(x::xs,ys);

- fun listOf(xs) = xs
= | listOf(x::xs) = [x]::listOf(xs);

I'm trying to use pattern match and I'm a little confused on it. I'm pretty sure x is the head and then xs is the tail, but I could be wrong. So what I'm trying to do is use the head of the list, make it a list, and then add it to the rest of the list. But when trying to do this function, I get the error:

stdIn:15.19-15.34 Error: operator and operand don't agree [circularity]
  operator domain: 'Z list * 'Z list list
  operand:         'Z list * 'Z list
  in expression:
    (x :: nil) :: listOf xs

This error is foreign to me because I don't have really any experience with sml/nj. How can I fix my listOf function?


Solution

  • You are fairly close. The problem is that in pattern-matching, a pattern like xs (just a variable) can match anything. The fact that you end it with s doesn't mean that the pattern can only match a tail of a list. Using s in that way is just a programmer convention in SML.

    Thus, in your definition:

    fun listOf(xs) = xs
    |   listOf(x::xs) = [x]::listOf(xs);
    

    The first line tells SML to return all values unchanged, which is clearly not your intent. SML detects that this is inconsistent with the second line where you are trying to change a value after all.

    You need to change that first line so that it doesn't match everything. Looking at that merge function as a template, you need something which matches a basis case. The natural basis case is nil (which can also be written as []). Note the role that nil plays in the definition of merge. If you use nil instead of xs for the pattern in the first line of your function definition, your second line does exactly what you want and the function will work as intended:

    fun listOf(nil) = nil
    |   listOf(x::xs) = [x]::listOf(xs);