Values, Names, and Procedures

Distinguish values, names, and calls. Use define, let, and lambda to build a reusable procedure.

You will define a procedure, give values names, and predict the result of nested calls. You will also use let to keep a name local to one calculation.

Start with First Program. Run each example separately in the Playground. The results below use its automatic display of top-level values.

The width example uses a trim width of 20 cm and 3 cm of total bleed across both edges. The sum is 23 cm.

Write values directly

LISPEX
42
#t
"Lispex"
#\L
'ready

The Playground shows these five values.

42
#t
"Lispex"
#\L
ready

These are a number, a boolean, a string, a character, and a symbol. A boolean is a true or false value, written #t or #f. #\L is the single character L. "Lispex" is a string.

A symbol is a value such as ready that can serve as a name in code. Written as ready, it tells Lispex to look up that name's value. Written as 'ready, it returns the symbol itself. The leading quote keeps it as data.

Follow a nested call

LISPEX
(+ 10 (* 2 3))

Result

OUTPUT
16

Lispex looks up +, evaluates 10, then evaluates (* 2 3) from left to right. The inner call returns 6. The outer call adds 10 and 6.

An ordinary call evaluates its arguments before calling the procedure. Forms such as define, lambda, let, and if have their own evaluation rules. Those rules also determine where you can use a name.

Give a value a name

LISPEX
(define bleed 3)
(+ 20 bleed)

Result

OUTPUT
23

Here define gives the value 3 the name bleed. Later expressions in the file can use that name. A repeated top-level define updates the existing name's value.

The definition produces no value to display. The Playground shows 23 from the addition.

Keep a name local

LISPEX
(let ((margin 7))
  (* margin 2))

Result

OUTPUT
14

let gives 7 the name margin within its body, (* margin 2). This local name is available only in that body. A name's scope is the part of the program where you can use it.

Create a reusable procedure

LISPEX
(define (width-with-bleed trim-width bleed)
  (+ trim-width bleed))

(width-with-bleed 20 3)

Result

OUTPUT
23

This defines a procedure with two input names, trim-width and bleed. The call gives them the values 20 and 3. The body adds those values.

You can write the same definition using lambda.

LISPEX
(define width-with-bleed
  (lambda (trim-width bleed)
    (+ trim-width bleed)))

lambda creates the procedure value, and define names it width-with-bleed. This definition alone displays nothing. The procedure requires two arguments. Passing one or three causes a runtime error.

Put the pieces together

LISPEX
(define (width-with-bleed trim-width bleed)
  (+ trim-width bleed))

(list (width-with-bleed 20 3)
      (let ((margin 7))
        (* margin 2)))

Result

OUTPUT
(23 14)

list constructs a list from its arguments. Lispex computes the first argument, 23, then the second, 14. list receives those values and returns (23 14).

Exercise

Define a procedure named triple that multiplies its input by 3. Call it twice inside list to produce (12 21).

Show one answer
LISPEX
(define (triple n)
  (* n 3))

(list (triple 4) (triple 7))

The result is (12 21).

You can now trace the nested call and identify where margin is available. Continue to Code Is Data to compare calls with quoted lists.