When this matters
Write a procedure to reuse a calculation or pass it to another procedure. Use apply when some or all of its arguments are stored in a list.
See it run
Save this complete program as procedures.lspx. Install the Native CLI first, or run each example separately in the Playground.
(define (sum first . rest) (apply + first rest))
(sum 1 2 3 4)lispex run procedures.lspxOutput
10The command exits with status 0 and creates no files.
Read the example
sum requires at least one argument. first receives 1, while rest receives the fresh list (2 3 4). apply combines the explicit first argument with that list and invokes + once.
The names first and rest are parameters. The values supplied by a call are arguments. The number of arguments a procedure accepts is its arity. The dot before rest means that this parameter collects the remaining arguments into a new list.
The expression (apply + first rest) is the procedure's body, the code that runs when it is called. In this example, it has the same effect as (+ 1 2 3 4).
Define names inside a procedure
(define (g)
(define a 1)
(define b 2)
(+ a b))
(g)Observed result
3The definitions of a and b create names local to g. Consecutive define forms at the start of a body are grouped together. Procedures defined in this group can call each other.
Keep these definitions together at the top. A define after another expression is outside that initial group.
Choose parameters and a call form
Use define to name a procedure. Use lambda to create a procedure value without naming it. Both find names according to the surrounding source structure, following the lexical scope rules. A procedure that keeps access to those names is called a closure.
| Shape | Best use | Arity |
|---|---|---|
(define (f x) body) | a named reusable procedure | fixed |
(lambda (x y) body) | an anonymous procedure value | fixed |
(define (f . xs) body) | a named procedure that gathers its arguments | zero or more |
(lambda (x . rest) body) | required arguments plus a remainder | at least the fixed prefix |
(apply f a final-list) | arguments assembled as data | checked by f |
The ... in (x ...) and (x ... . rest) means more parameter names, not literal source text. These are the two accepted shapes for a lambda parameter list. A bare name without parentheses, as in (lambda args ...), raises E130.
A rest parameter receives a new proper list, whose final tail is (). apply also requires its final argument to be a proper list. For example, '(1 2) is proper, while '(1 . 2) ends in 2 and is improper.
Check arguments before the body runs
Lispex evaluates the procedure expression first, then the argument expressions from left to right. An argument count mismatch raises E302 before the body runs. For example, (sum) supplies none of the arguments required by sum.
Calling a value that is not a procedure raises E301. An improper final list, such as in (apply + '(1 . 2)), raises E312.
Use apply for the last call
When apply is the final action in a procedure, it preserves tail position. The called procedure's result becomes the caller's result without adding a return step. See tail calls for examples.
Lispex uses the same call handler for direct calls and apply. It executes Lispex closures itself; it does not delegate them to the implementation language's apply.
Keep going
Higher-order procedures explains passing procedures to operations such as map and filter. The closures guide shows how a procedure keeps access to names after the surrounding code returns.