WhizzML Reference Manual

2.5 Maps and lists as procedures

List values can be used as procedures that, when applied to an integer value, return the value in the list at that position. In other words, lists can be interpreted as a procedure that maps integers to values. For instance:

(["a" "b" "c"] 0) ;; => "a"
(let (l [1 2 3]) [(l 2) (l 0) (l 1) (l 2)]) ;; => [3 1 2 3]

Besides the index, one can provide a default value to return if the position is out of bounds:

(["a" "b" "c"] 0 "d") ;; => "a"
(["a" "b" "c"] 3 "d") ;; => "d"

The action of lists as procedures is easily described in terms of the nth primitive (see subsection 4.7.2 ). If <list> is an arbitrary list, <n> an integer and <x> any WhizzML value, we have the identities:

(<list> <n>) := (nth <list> <n>)
(<list> <n> <x>) := (nth <list> <n> <x>)

In a similar way, map values can be used as procedures that perform lookups of the key or key paths passed as first argument, with a second optional argument denoting the value to return if the given key or key path is not found. When a default value is not given, the map signals an error with code -15. For instance:

(let (m {"age" 24238 "name" "Treebeard"}
      p {"ent" m "other" 0})
  (m "age")  ;; => 24238
  (m "size") ;; => false
  (m "size" "huge")  ;; => "huge"
  (p ["ent" "name"]) ;; => "Treebeard"
  (p ["ent" "name"] "Lev") ;; => "Treebeard"
  (p ["a" "name"]) ;; => * Error (code -15) *
  (m ["age" "day"])) ;; => * Error (code -15) *

Note that if <s_n> are arbitrary string values, <map> a map and <x> an arbitrary default value, the following identities hold:

(<map> (list <s_0> <s_1> ... <s_n>)) := ((<map> <s_0>) (list <s_1> .. <s_n>))
(<map> (list <s_0> <s_1> ... <s_n>) <x>) := ((<map> <s_0>) (list <s_1> .. <s_n>) <x>)

The action of maps as procedures can also be described in terms of the primitives get and get-in (see subsection 4.9.2 ) as follows:

(<map> <s>) := (get <map> <s>)
(<map> <s> <x>) := (get <map> <s> <x>)
(<map> (list <s_0> ... <s_n>)) := (get-in <map> (list <s_0> ... <s_n>))
(<map> (list <s_0> ... <s_n>) <x>) := (get-in <map> (list <s_0> ... <s_n>) <x>)

Lookups using a list of keys generalize to mixed lists of keys and positions, so that a composite value consisting of maps and lists can be traversed in a single call, using it in the function position. That behavior is inherited from the get-in primitive. For instance:

(let (m {"kind" "split"
         "children" [{"kind" "number" "value" 42}
                     {"kind" "list" "value" [1 2 3]}]}
      ls [0 m [1 2 3] m])
  (m ["children" 0]) ;; => {"kind" "number" "value" 42}
  (m ["children" 0 "value"]) ;; => 42
  (m ["children" 1 "value" 2]) ;; => 3
  (m ["children" 2 "value" 2]) ;; => * Error (code -15) *
  (ls [1 "kind"]) ;; => "split"
  (ls [2 2]) ;; => 3
  (ls [3 "children" 1 "value" 2])) ;; => 3

Despite the fact that maps and lists can behave as procedures, the primitive procedure? returns false when applied to map and list values.