Generics in Standard ML

(* Starting with version 1.18, SML has added support for
   _polymorphic types_, which are similar to generics in other languages. *)

(* As an example of a polymorphic function, `slicesIndex` takes
   a list of any comparable type and an element of that
   type and returns the index of the first occurrence of
   v in s, or ~1 if not present. The `''a` type variable
   indicates that the type must support equality comparison. *)

fun slicesIndex (s : ''a list) (v : ''a) : int =
    let
        fun loop [] _ = ~1
          | loop (x::xs) i = if x = v then i else loop xs (i+1)
    in
        loop s 0
    end;

(* As an example of a polymorphic type, `List` is a
   singly-linked list with values of any type. *)

datatype 'a List = Nil | Cons of 'a * 'a List;

(* We can define functions on polymorphic types just like we
   do on regular types, but we have to keep the type
   parameters in place. The type is `'a List`, not just `List`. *)

fun push (lst : 'a List ref) (v : 'a) : unit =
    case !lst of
        Nil => lst := Cons(v, Nil)
      | Cons(_, _) =>
        let fun append Nil = Cons(v, Nil)
              | append (Cons(x, xs)) = Cons(x, append xs)
        in lst := append (!lst)
        end;

(* allElements returns all the List elements as a list. *)

fun allElements (lst : 'a List) : 'a list =
    let fun loop Nil acc = List.rev acc
          | loop (Cons(x, xs)) acc = loop xs (x::acc)
    in loop lst []
    end;

(* Main function to demonstrate usage *)

fun main () =
    let
        val s = ["foo", "bar", "zoo"]
        val _ = print ("index of zoo: " ^ Int.toString (slicesIndex s "zoo") ^ "\n")

        val lst = ref (Nil : int List)
        val _ = push lst 10
        val _ = push lst 13
        val _ = push lst 23
        val elements = allElements (!lst)
        val elementsStr = String.concatWith " " (List.map Int.toString elements)
        val _ = print ("list: " ^ elementsStr ^ "\n")
    in
        ()
    end;

(* Run the main function *)
val _ = main ();

This Standard ML code demonstrates concepts similar to generics in other languages, using SML’s polymorphic types. Here’s a breakdown of the translation:

  1. The SlicesIndex function is translated to slicesIndex, using SML’s pattern matching and recursion to implement the search.

  2. The List type is implemented as a recursive datatype 'a List, which is a common way to represent linked lists in SML.

  3. The Push method is translated to a push function that takes a reference to a list and modifies it in-place.

  4. The AllElements method is translated to allElements, which converts our custom List type to a standard SML list.

  5. The main function demonstrates the usage of these polymorphic functions and types.

To run this program, you would typically save it to a file (e.g., generics.sml) and then use an SML interpreter or compiler. For example, using the Standard ML of New Jersey (SML/NJ) system:

$ sml generics.sml
index of zoo: 2
list: 10 13 23

This example showcases how SML handles polymorphic types and functions, which serve a similar purpose to generics in other languages. The syntax and approach are different, but the core concepts of type parameterization and code reuse are present.