Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Functions

A lambda takes exactly one argument, and names itself:

(lambda self arg body)

The first symbol is the function’s name for its own body; the second is the parameter. Application is juxtaposition:

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

When the self-name is not needed, the convention is to write _ for it — _ is an ordinary symbol, not special syntax, and the convention is inherited from the reference implementation.

Recursion

When a closure is applied, its environment is extended with the closure itself and then the argument, so the body reaches its own function under the self-name. Recursion therefore needs no fixpoint combinator and no top-level definition:

((lambda fact n
   (if (eq? n 0)
       1
       (* n (fact (- n 1)))))
 5)
;=> 120

fact is in scope only inside the body. This is the language’s whole story about recursion, and it is enough: every recursive function in the system’s libraries — append, map, the Pink evaluator itself — is written this way.

Currying

One argument per lambda means multi-argument functions are curried: a function of two arguments is a function returning a function.

(let add (lambda _ a (lambda _ b (+ a b)))
  ((add 2) 3))
;=> 5

Application sugar makes the call sites bearable: (f a b) reads as ((f a) b), associating left, for any number of arguments.

(let add (lambda _ a (lambda _ b (+ a b)))
  (add 2 3))
;=> 5

There is no corresponding sugar on the binding side — a two-argument function is written as two nested lambdas, and only the outer one can usefully carry a self-name (an inner lambda’s self-name rebinds on every call, capturing the partial application rather than the whole function). The library convention is to name the lambda that drives the recursion and write _ for the rest; lib/prelude.naj is a compact style guide.

Partial application falls out for free:

(let add (lambda _ a (lambda _ b (+ a b)))
  (let increment (add 1)
    (increment 41)))
;=> 42

Closures print as #<closure>:

(lambda _ x x)
;=> #<closure>