Immutable, singly linked lists are part of the core language. Elements in a given list must be of a single type.
[][elt1, elt2, …,
        eltn]elt :: listThe prepend operator :: is called cons
        and it is right-associative. Writing a full list
        [elt1, elt2, …,
            eltn]
    
    is just shorthand for
        elt1 :: elt2 ::
        … :: eltn :: []
    
The type of a list includes the type of the elements it contains
- [1,5,9]; > val it = [1, 5, 9] : int list - [[], [3], [7,8]]; > val it = [[], [3], [7, 8]] : int list list - "three" :: ["blind", "mice"]; > val it = ["three", "blind", "mice"] : string list - [(1, true), (2, false), (3, true)]; > val it = [(1, true), (2, false), (3, true)] : (int * bool) list
Lists are immutable and can only be modified by prepending new elements
- (0, false) :: it; > val it = [(0, false), (1, true), (2, false), (3, true)] : (int * bool) list
Data constructors are also used to deconstruct data. A pattern match occurs when an expression is given that could have created the data being matched, given the right bindings to the names that appear.
Names that appear in the pattern are bound to the
    corresponding parts of the data object.  Constants require an
    exact match, and _ matches anything without binding
    it to a name.
- fun null [] = true
    | null (x::xs) = false;
> val 'a null = fn : 'a list -> bool
- fun fact 1 = 1
    | fact n = n * fact (n - 1);
> val fact = fn : int -> int
    Patterns can be used in function definitions
        (fun and fn),
        val bindings, and explicit
        case ... of ... end
        expressions.
Value bindings are always done through pattern matches. Any data constructors—built-in or user defined— can appear in a pattern.
- val a :: [b, c] = [5, 6, 7];
> val a = 5 : int
  val b = 6 : int
  val c = 7 : int
- val x :: y :: z = [1,2,3,4,5];
> val x = 1 : int
  val y = 2 : int
  val z = [3, 4, 5] : int list
- fun first (a, _) = a;
> val ('a, 'b) first = fn : 'a * 'b -> 'a
- fun getfirst x = first x;
> val ('a, 'b) getfirst = fn : 'a * 'b -> 'a
    Pattern matching is the only way to access the constituents of a data structure.
Patterns can be as deep or as shallow as required. They can match a value or the components that make up that value.
- val x = [(1, ([(2, "hi", true), (3, "yo", false)]))]; > val x = [(1, [(2, "hi", true), (3, "yo", false)])] : (int * (int * string * bool) list) list - val y :: z = x; > val y = (1, [(2, "hi", true), (3, "yo", false)]) : int * (int * string * bool) list val z = [] : (int * (int * string * bool) list) list - val (a, ((b, c, d) :: e)) :: [] = x; > val a = 1 : int val b = 2 : int val c = "hi" : string val d = true : bool val e = [(3, "yo", false)] : (int * string * bool) list
Only one pattern can be used with val, but
    fun, fn, and case expressions
    can include multiple patterns. They are tried in order until one
    one matches the shape of the object being matched.
To compute the length of a list, count its elements recursively
- fun length [] = 0
    | length (_::xs) = 1 + length xs;
> val 'a length = fn : 'a list -> int
    To get the head of a list, pattern match for it
- fun hd (x::_) = x; > Toplevel input: ! fun hd (x::_) = x; ! ^^^^^^^^^^^^^ ! Warning: pattern matching is not exhaustive > val 'a hd = fn : 'a list -> 'a
Similar for tl, the tail function.
Lists are immutable; to make changes you have to copy up to the point you make the change.
- fun append [] ys = ys
    | append (x::xs) ys = x :: (append xs ys);
> val 'a append = fn : 'a list -> 'a list -> 'a list
    Append is the infix operator @. We can use it
    for a simple (but awful) list reversal function
- fun badreverse [] = []                      
    | badreverse (x::xs) = badreverse xs @ [x];
> val 'a badreverse = fn : 'a list -> 'a list
    badreverse copies half the list on average in
    each step.
badreverse [1,2,3,4,5] => badreverse [2,3,4,5] @ [1] badreverse [2,3,4,5] => badreverse [3,4,5] @ [2] badreverse [3,4,5] => badreverse [4,5] @ [3] badreverse [4,5] => badreverse [5] @ [4] badreverse [5] => badreverse [] @ [5]
Another way to write the length function uses an
    accumulator to gather the running total
- fun length2 [] a = a
    | length2 (_::xs) a = length2 xs (a + 1);
> val 'a length2 = fn : 'a list -> int -> int
    This requires an extra argument. A local function defined and used inside another function lets us present the desired function type to the outside world while still passing an extra parameter in the main recursive loop.
Use
    let … in … end to
    define local functions and other values.
- fun length lst =
    let fun f [] a = a
          | f (_::xs) a = f xs (a + 1)
    in f lst 0
    end;
> val 'a length = fn : 'a list -> int
The better way to reverse a list uses the same idea; it requires an extra argument in the main recursive loop
- fun rev lst = 
    let fun f [] a = a
          | f (x::xs) a = f xs (x::a)
    in f lst []
    end;
> val 'a rev = fn : 'a list -> 'a list
    This version is sometimes called iterative, or tail recursive
while loopNot all functions can be made tail recursive. To be tail recursive, a function must do all of its work before passing all necessary data as arguments to the next iteration.
In general, operations that are commutative can be implemented with or without using tail recursion. If the order matters, then you are usually forced one way or the other.
When manipulating lists, tail recursive functions tend to reverse the list. You have to work from the head of a list, not the tail, and you can only prepend elements to a new list, not append them.
As a result, tail recursive functions that copy a list have the side-effect of reversing it. The last element from the source list becomes the first element of the new list. Compare these two copy functions
- fun copy1 (x::xs) = x :: (copy1 xs)
    | copy1 []      = [];
> val 'a copy1 = fn : 'a list -> 'a list
- fun copy2 lst =
    let fun f (x::xs) a = f xs (x::a)
          | f [] a = a
    in f lst []
    end;
> val 'a copy2 = fn : 'a list -> 'a list
We can turn a pair of lists into a list of pairs
- fun zip (x::xs, y::ys) = (x,y) :: zip (xs, ys)
    | zip _              = [];                
> val ('a, 'b) zip = fn : 'a list * 'b list -> ('a * 'b) list
    Note that _ (or a name) can match a compound
    value as well as simple values. Pattern matches are
    evaluated in the order they are written, so the second pattern
    acts as a fallthrough that catches anything the first pattern
    misses.
unzip reverses the actions of zip
- fun unzip ((x,y) :: tail) = let val (xs, ys) = unzip tail
                              in (x::xs, y::ys)
                              end
    | unzip [] = ([], []);
> val ('a, 'b) unzip = fn : ('a * 'b) list -> 'a list * 'b list
Using name as pattern
    we can name an item and its subcomponents at the same time
- fun insertinorder n (lst as x::xs) =
          if n <= x then n :: lst
          else x :: (insertinorder n xs)
    | insertinorder n _ = [n];
> val insertinorder = fn : int -> int list -> int list
    Note that insertinorder copies the list until it
    finds the insertion point, then it points to the remainder of the
    existing list.
Lists are immutable, so the remainder of the old list is just as good as a new copy. It can't change.