Scheme Programming/Procedures
So far, we've worked with many built-in Scheme procedures (like +, *, etc.), but we haven't seen how to define our own. Procedures are created with the lambda form. Here's a simple example:
> (lambda (x) (* x x))
#<procedure>
Evaluating a lambda
form gives us back a procedure object,
which we can treat like any other value.
Unlike the built-in procedures that we've been working with, though,
this procedure lacks something important--a name. The procedures
constructed with lambda are thus called "anonymous"; if we want to
apply them, we have to write out the lambda expression as the operator
of an application:
> ((lambda (x) (* x x)) 4)
16
How does this work? As we saw in previous sections, we evaluate an
application of a
procedure to some arguments by first evaluating both the operator
(which is (lambda (x) (* x x))
here) and the operands.
Our lambda expression evaluates to an (anonymous) procedure of one
argument, x, which returns the value of x squared.
Applied to the value 4, this procedure returns 16.
Naming procedures
editIt's impractical--though certainly not impossible--to write programs using only anonymous procedures. Even relatively simple programs would become unbearably complicated if we had to write lambda expressions for every operator, rather than using convenient names. Since procedures are values, we can gives names to them with define, just as we can any other value:
> (define square (lambda (x) (* x x)))
> (square (square 2))
16
Here, we define square
to mean the procedure
(lambda (x) (* x x))
. Once this is done, we can use
square as a procedure anywhere we like. Scheme makes
no distinction between built-in and newly-defined procedures, so
procedure definitions are a crucial way in which Scheme programmers
extend the language.
It's a bit clumsy to have to write
(define <name> (lambda (<arg> ...) ...))
every time
we want to write a procedure, so Scheme provides a shorthand. We
can also write our definition of square as follows:
(define (square x)
(* x x))
The general form of this shorthand is:
(define (<name> <arg> ...) <body>)
This definition is the same as the one with the explicit lambda expression, but it's a little quicker to type. You'll see this form of definition constantly in Scheme code.
Variable number of arguments
editYou can also create procedures with a variable number of arguments:
(define (sum . args)
(apply + args))
This will create procedure sum which works identically to the native + procedure.
This is the same as:
(define sum (lambda args
(apply + args)))
Note that there are no parentheses around the args parameter so all arguments will be put into one list named args.
With lambda, if you want to have one fixed argument and the rest of the arguments optional you can use an improper list:
(define sum (lambda (first . rest)
(/ first (apply + rest))))
With this, you can create procedures with optional arguments:
(define (rational first . rest)
(let ((second (if (null? rest) 1 (car rest))))
(/ first second)))
This will create a procedure that evaluates (/ first 1)
when no second argument is provided or (/ first second)
.