WhizzML Reference Manual

2.4 Procedures

User-defined procedure values are created using the lambda keyword, with the following syntax for lambda expressions :

(lambda [<name>] <formals> <body>)

<name> ::= optional identifier for recursive calls in <body>
<formals> ::= (<id_1> ... <id_n>) || (<id_1> ... <id_n> . <id_n+1>)
   where <id_i> are identifiers
<body> ::= list of valid whizzml expressions

As shown, <formals> must have one of the following forms:

  • (<id_1> ... <id_n>): The procedure takes a fixed number of arguments. The number of arguments can be zero, in which case <formals> is just the empty list, .

  • (<id_1> ... <id_n> . <id_n1>)+: If a space-delimited period precedes the last variable, then the procedure takes \(n\) or more arguments, where \(n\) is the number of formal arguments before the period (\(n\) can be zero). The value stored in the binding of the last variable will be a newly allocated list of the actual arguments left over after all the other actual arguments have been matched up against the other formal arguments.

A lambda expression evaluates to a procedure that can be called directly:

((lambda (x) (+ x 1)) 41)   ;; => 42

The optional <name> identifier can be used to refer to the lambda procedure itself within its body, for recursive definitions. For instance, this lambda expression computes the factorial of its argument:

(lambda fact (x) (if (> x 1) (* x (fact (- x 1))) 1))

As mentioned, fact is in scope only within the lambda’s body, where it’s bound to the procedure value itself. So we have:

((lambda fact (x) (if (> x 1) (* x (fact (- x 1))) 1)) 5) ;; => 120
(let (f (lambda fact (x) (if (> x 1) (* x (fact (- x 1))) 1)))
  (f 5)) ;; => 120
(let (fact (lambda fact (x) (if (> x 1) (* x (fact (- x 1))) 1)))
  (fact 5)) ;; => 120

or assigned a name with define, and subsequently applied using that name:

(define inc (lambda (x) (+ 1 x)))
(inc 41)

The <formals> (possibly empty) list can contain only valid identifiers and can have no duplicates. Some examples:

(lambda (x y) (+ y x))
(lambda () (rand-int 23))

and using a period separator we can denote a variable number of arguments:

((lambda (x y . z) z) 1 2 3 4 56) ;; => [3 4 56]
((lambda (. z) z) 1 2 3 4 56) ;; => [1 2 3 4 56]
((lambda (x . z) z) 1) ;; => []

See also subsection 3.2.3 for additional syntactic sugar used to name user-defined procedures.