Data, Conditions, and Decisions

Use quoted data, if, cond, and short-circuit logic to return a decision as a list.

You will write a condition that selects a decision and returns it as a list. You will also predict which expressions if, and, or, and cond evaluate.

Read Code Is Data first. Run each example separately in the Playground to see its result.

Keep data with quote

LISPEX
(+ 1 2)

Result

OUTPUT
3

This expression calls +. A quote returns the list as data.

LISPEX
'(+ 1 2)

Result

OUTPUT
(+ 1 2)

Use quote for fixed data. Use list to construct a list from evaluated arguments.

LISPEX
(list 'decision 'keep)

Result

OUTPUT
(decision keep)

Here both arguments return symbols. You can also pass expressions that compute the elements, as you did in the previous lesson.

Choose between two results with if

LISPEX
(if (< 1 2)
    '(decision next-page)
    '(decision keep))

Result

OUTPUT
(decision next-page)

if has a test and two result expressions. One remaining line is less than two, so it selects '(decision next-page). It evaluates only that branch.

Only #f is false. The number 0, the empty string "", and the empty list () all count as true. To test whether a number is positive or a list is empty, use a predicate, a procedure that returns #t or #f.

Stop early with and and or

LISPEX
(and (> 5 1)
     (not #f))

Result

OUTPUT
#t

(> 5 1) returns #t, so and continues to (not #f), which also returns #t. not returns #t for #f and #f for every other value.

and evaluates expressions from left to right and stops at the first #f. or also evaluates from left to right, but stops at the first value other than #f. Later expressions are skipped. This is called short-circuit evaluation.

LISPEX
(or #f 'standard)

Result

OUTPUT
standard

or skips past #f and returns the symbol standard. For calls with arguments, and and or return the value where they stop. If neither stops early, it returns the last argument's value. These values are not converted to booleans.

Choose among several cases with cond

LISPEX
(define (heading-decision lines-left chapter-heading?)
  (cond
    ((< lines-left 2) '(decision next-page))
    (chapter-heading? '(decision new-chapter))
    (else '(decision keep))))

(heading-decision 5 #t)

Result

OUTPUT
(decision new-chapter)

cond tests cases from top to bottom. With five lines left, the first test is false. The chapter-heading flag is true, so it selects new-chapter. Fewer than two lines select next-page first. If both tests are false, else selects keep. The symbol decision labels the answer.

Inspect a list

LISPEX
(define answer '(decision keep))
(list (car answer) (car (cdr answer)))

Result

OUTPUT
(decision keep)

For a non-empty list, car returns its first element and cdr returns the remaining list. Here (car answer) returns decision. (car (cdr answer)) returns keep. list puts them back together.

In a rule, construct the result directly when possible. If you repeatedly extract the same part of a list, a named helper procedure can make that operation easier to read.

Exercise

Write margin-decision to keep a margin of at least 18 mm and widen a smaller margin.

Show one answer
LISPEX
(define (margin-decision margin-mm)
  (if (>= margin-mm 18)
      '(decision keep)
      '(decision widen narrow-margin)))

(margin-decision 17)

The result is (decision widen narrow-margin).

Explain how '(decision keep) differs from (decision keep), then name the three parts of if. Continue to First Decision Rule to apply these ideas in a complete rule.