Search code examples
smlsmlnjml

Just Started Learning SML: How to take two ints and return the list of all ints between


Pretty much what the title says. I just started learning SML and am having trouble with my first project. I understand this is a very basic question and it would be incredibly easy for me to do in something like java, but I'm having difficulty understanding SML. I need to write a function intsFromTo. It should take a pair of integers, low and high, and return a list of consecutive integers in ascending order, namely all those that are greater than or equal to low and less than or equal to high.

Here's what I have so far

fun intsFromTo (low,high) = val intList = []
if low >= high then nill
else intList::low intsFromTo(low+1,high);

and I'm getting the following errors which I'm also having difficulty understanding.

https://i.sstatic.net/hMRRR.png

Any and all help to get me going would be greatly appreciated.


Solution

  • Note: The code could be mode more compact for style but might not so clearly illustrate the basic concepts.

    Typical Recursion

    fun intsFromTo(low, high) =
      let
          val out = []
      in
          if 
              low <= high
          then
              low :: intsFromTo2(low + 1, high)
          else
              out
      end
    

    Alternative Approach

    An alternative way to produce the list is using map-reduce style semantics on a list.

    fun intsFromTo(low, high) =
      if high > low         
      then     (* the list will contain at least one value *)
         if
           high >= 0
         then
           List.tabulate((high + 1) - low,
                    fn k => k + low)
         else
           List.rev(
              List.tabulate((~low + 1) + high,
                    fn k => ~k + high))
      else
          []    (* list empty: low >= high *)
    

    Why an Alternative? Just out of curiosity.

    Performance

    Anecdotal timing indicates that the first version is about twice as fast as the second version using:

    fun time() =
      let 
          val t = Timer.startCPUTimer();
      in
          intsFromTo(~1000000,1000000);
          Time.toReal(#usr(Timer.checkCPUTimer(t)))
      end
    

    At least on my computer while it is being used for other things.