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>