Range Over Iterators in Standard ML

Our aim is to demonstrate the usage of Standard ML functions and iterators with various examples. Here’s the full source code translated into Standard ML.

First, we will define our List type and necessary functions.

(* Define the List type and functions *)
datatype 'a element = Element of { value: 'a, next: 'a element option }

datatype 'a List = List of { mutable head: 'a element option, mutable tail: 'a element option }

fun createList () = List { head = NONE, tail = NONE }

fun push (List { head, tail }) value = 
    let
        val new_elem = SOME (Element { value = value, next = NONE })
    in
        case tail of
            NONE => (head := new_elem; tail := new_elem)
          | SOME (Element { next, ... }) => (next := new_elem; tail := new_elem)
    end

Let’s look at the List type. In the above example, we have defined a push function to add elements to the list. Now, let’s create a function that will return an iterator over the list.

(* Function to iterate over all elements in the list *)
fun all (List { head, _ }) yield = 
    let
        fun aux NONE = ()
          | aux (SOME (Element { value, next })) = 
              if yield value then aux next else ()
    in
        aux head
    end

Here, we define an all function that takes a list and a yield function which is invoked for each element until early termination if needed.

Next, we’ll demonstrate generating Fibonacci numbers using a function that returns an iterator.

(* Fibonacci generator function *)
fun genFib yield =
    let
        fun aux a b = 
            if yield a then aux b (a + b) else ()
    in
        aux 1 1
    end

This function genFib will generate Fibonacci numbers indefinitely until yield returns false.

We will see how to use these iterators in practical scenarios.

(* Example usage *)
val lst = createList ()
val () = push lst 10
val () = push lst 13
val () = push lst 23

(* Print all elements in the list *)
val () = all lst (fn x => (print (Int.toString x ^ "\n"); true))

(* Collect all elements in a list *)
val allElements = ref [] 
val () = all lst (fn x => (allElements := !allElements @ [x]; true))
val () = print ("all: [" ^ String.concatWith " " (List.map Int.toString (!allElements)) ^ "]\n")

(* Print Fibonacci numbers less than 10 *)
val () = genFib (fn x => (if x >= 10 then false else (print (Int.toString x ^ "\n"); true)))

With the above code, you can manage elements in a custom list and generate Fibonacci numbers in Standard ML.

Let’s summarize the key points:

  1. Define List and element types: Custom types handling the list and element structure.
  2. Push function: Add elements to our list.
  3. Iterator function all: Iterate over elements in the list using a yielding function.
  4. Fibonacci generator: Generate Fibonacci numbers using an iterative function and yield.

You can try running these code snippets on an SML interpreter to see how iterators work along with custom list management.

Now that we have explored iterators and custom lists in Standard ML, let’s dive deeper into more advanced topics in the language.