Scheme Programming/Procedures

Scheme Programming
 ← Conditionals Procedures Looping → 

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

edit

It'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

edit

You 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).