This is an earlier edition of the documentation. To define and call procedures, open the current procedure manual. For counters that remember their state, see Closures and Counter State.
In Lispex, functions are the primary building blocks for logic and abstraction. Functions are first-class citizens: you can bind them, pass them, and return them.
Defining Functions
Create named functions with define sugar, and anonymous functions with lambda.
Named Functions with define
(define (add x y)
(+ x y))
(add 5 10) ; ⇒ 15Anonymous Functions with lambda
(lambda (n) (* n 2))Functions as First-Class Citizens
Being "first-class" means functions are treated like any other data value (such as a number or a list). They can be:
1. Stored in bindings
Bind functions like any other value.
(define square (lambda (n) (* n n)))
(define square-alias square)
(square-alias 10) ; ⇒ 1002. Passed as Arguments
You can pass functions as arguments to other functions. This is fundamental to higher-order functions.
(define (apply-it f v)
(f v))
(define square (lambda (n) (* n n)))
(apply-it square 10) ; ⇒ 1003. Returned from Other Functions
A function can create and return another function. This powerful pattern is explained in the "Closures" section below.
Understanding Closures
When a function is created, it captures the environment (the variables and their values) in which it was defined. This captured environment is called a closure. This allows a function to "remember" values, even when it's called outside of its original scope.
Example: A Function Factory
(define (make-adder amount-to-add)
(lambda (n)
(+ n amount-to-add)))
(define add-five (make-adder 5))
(define add-ten (make-adder 10))
(add-five 100) ; ⇒ 105
(add-ten 100) ; ⇒ 110Recursion
In Lispex, iteration is most idiomatically achieved through recursion. This approach avoids side effects and state mutations.
(define (factorial n)
(if (<= n 1)
1
(* n (factorial (- n 1)))))
(factorial 5) ; ⇒ 120