Search code examples
functional-programmingsmlsmlnjml

Given a list create a list of tuples SML


Hello I am new to Sml/nj, and I am trying to modify an input to give it to a function. I'm stuck at modifying the input.

Specifically, I read the input and store it in a list. I want to make a function that given an even length list, it will make a new list, but with 2-element tuples.
For example, if my input is the list [2, 7, 4, 6, 5, 8] I want to create this list [(2, 7), (4, 6), (5, 8)]

I tried this but unfortunately it doesn't work:

fun maketuples [] = []
  | maketuples x::xs = (x, hd xs) @ makektuples (tl xs)

Solution

  • There's a couple things here:

    • If you're pattern matching on a constructor as a function argument, you need to put parentheses around it for it to be parsed the way you'd like, i.e., x::xs -> (x::xs)

    • You have a typo in the second clause (makektuples; extra k)

    • You're using append (@) on a int * int and a (int * int) list. The domain of this function is in fact, 'a list * 'a list, i.e., both of its arguments must be lists of the same type.

    We could revise this like so:

    fun maketuples [] = []
      | maketuples (x::xs) = [(x, hd xs)] @ maketuples (tl xs)
    

    But singleton append isn't really something you should do. Why? It's cleaner to just use cons:

    fun maketuples [] = []
      | maketuples (x::xs) = (x, hd xs) :: maketuples (tl xs)
    

    We can clean this up some more by removing the calls to hd and tl by just destructing further in the function arguments

    fun maketuples [] = []
      | maketuples (x::y::xs) = (x, y) :: maketuples xs
    

    and you could perhaps handle an error better (one possibility being with exceptions):

    fun maketuples [] = []
      | maketuples (x::y::xs) = (x, y) :: maketuples xs
      | maketuples _ = raise Fail "Not an even length list"