Search code examples
functional-programmingsmlsmlnj

How to keep elements in list through out the program in SML?


Suppose I have to update a list with each call to a function, such that, the previous element of the list are preserved.

Here is my attempt:

local 
    val all_list = [];
in
    fun insert (x:int) : string  = int2string (list_len( ((all_list@[x])) ) )
end;

The problem is that each time I call to insert, I get the output "1", which indicates that the list is initiated to [] again.

However I was expecting output of "1" for the first call to insert, and "2" for the second call,...etc.

I am not able to come with a workaround. How should it be done?


Solution

  • You need to use side-effects. Most of the time functional programmers prefer to use pure functions, which don't have side effects. Your implementation is a pure function, so it will always return the same value for the same input (and in your case it returns the same value for any input).

    You can deal with that by using a reference.

    A crash course on references in Standard ML:

    • use ref to create a new reference, ref has type 'a -> 'a ref, so it packs an arbitrary value into a reference cell, which you can modify later;
    • ! is for unpacking a reference: (!) : 'a ref -> 'a, in most imperative languages this operation is implicit, but not in SML or OCaml;
    • (:=) : 'a ref * 'a -> unit is an infix operator used for modifying references, here is how you increment the contents of an integer reference: r := !r + 1.

    The above gives us the following code (I prepend xs onto the list, instead of appending them):

    local
        val rxs = ref []
    in
        fun insert (x:int) : string =
          (rxs := x :: !rxs;
           Int.toString (length (!rxs)))
    end