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:
The
SlicesIndex
function is translated toslicesIndex
, using SML’s pattern matching and recursion to implement the search.The
List
type is implemented as a recursive datatype'a List
, which is a common way to represent linked lists in SML.The
Push
method is translated to apush
function that takes a reference to a list and modifies it in-place.The
AllElements
method is translated toallElements
, which converts our customList
type to a standard SML list.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.