Making your own words
Lambda, the two ways to name a function, local helpers, and the idea that a function is a value you can hand to another function.
A function is a value
A lambda builds a function: (lambda (x) (+ x 1)) is a function that adds one to whatever it is handed. The bracketed list after lambda names its parameters, and the expression after that is its body. On its own it does nothing at all — it is a value, waiting for arguments, exactly like the number 7 waits to be printed.
Because it is a value, you can give it a name, keep it in a list, or pass it to another function. That last ability is the one that changes how programs are written, and you will meet it again in the chapter on map and filter.
The short spelling, and helpers
The bracketed spelling of define is the same thing in a friendlier shape: write the name, then its parameters in brackets, and define knows you are describing a function. Both spellings build identical values, so use whichever reads better where you are writing.
A body may hold several expressions, and a function can define a helper of its own inside it. The helper is invisible from outside, which is a quiet gift: a name that only matters in one place does not clutter the rest of the program. The value of the last expression in the body is what the function answers with.
Arguments are values, parameters are names
A call works in two steps: evaluate every argument, then enter the body with each parameter bound to one of those values. (square (+ 2 3)) computes 5 first, so the body only ever sees the result.
The number of arguments must match the number of parameters. Too few or too many is an error before the body runs, which is why an arity mistake names the function rather than a line inside it.
A parameter is a fresh local name on every call. Two calls to the same function get separate bindings, so a recursive call does not overwrite the value the outer call is still using.
Scope, and functions that remember
A function body can see its parameters, the names defined inside it, and the names defined outside it. The innermost binding wins when two share a spelling.
A lambda keeps the names that were visible where it was written, not where it is called. That is why a helper defined inside one function cannot be reached from another, and why a function handed back from inside another function still remembers its private names.
This is lexical scope, and it is the reason a function is a value you can move around safely. The code travels with the names it needs.
Two spellings and a local helper
(define square (lambda (x) (* x x)))
(define (cube x) (* x x x))
(print (square 5))
(print (cube 3))
; A helper that only this function can see.
(define (area width height)
(define (product a b) (* a b))
(product width height))
(print (area 3 4))
; A function can be an argument.
(define (twice f x) (f (f x)))
(print (twice square 2))
(print (twice (lambda (n) (+ n 10)) 5))A call evaluates its arguments first
Scheme is eager: every argument is worked out before the function body begins. (square (+ 2 3)) computes 5, then enters square with x bound to 5. The body never sees the expression, only its value, which is why a function cannot change how its caller computed an argument.
That order also means an argument that fails stops the call before the body runs. An error that names the argument expression rather than the function is telling you the failure happened on the way in, not inside.
Two spellings, one value
(define square (lambda (x) ...)) and (define (square x) ...) build the same value; the second is a convenience. Because the value is ordinary, it can be passed, returned, and stored in a list. A function that takes another function is not a special feature; it is the consequence of functions being values.
The practical skill is reading the first position of a list. If it is a name bound to a function, the list is a call. If it is a lambda, the list is also a call, made on the spot. If it is a number, the list is malformed, and the error will say so.
Three common slips. Writing (square 5) is a call, but square 5 is two separate values and does nothing. A body of several expressions answers with the last one, so an early display is there for its effect, not its value. And a function must be defined before the line that calls it.
Try these next
- Write
(define (double n) (* n 2))and call it with an expression instead of a number. - Add a local helper to
averagethat adds two numbers, then call it twice. - Write a function that takes another function and applies it three times to 1.
Functions that take functions
Run it and follow the two calls to `twice`: one hands it a named function, the other a function written on the spot. Then write `(define (quadruple x) (twice square x))` and print its value for 2.
Shapes with a local helper
Run it and read the area and perimeter of each rectangle. Then add a `triangle` function with its own local helper, and print the Celsius value for 98.6.
A function answers with the value of the last expression in its body. When a body has several lines, the earlier ones are there for their effect — a display, a define — and the last one is the answer. You never write the word return.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
What does (lambda (x) (+ x 1)) do on its own?
