Skip to content

Land of Lisp - Ch 4

TL;DR

  • Empty equals false - all of these are empty -> () '() nil 'nil
  • if - only one branch (then branch or else branch) evaluated depending on condition
  • when and unless - implicit progn
  • cond - classic branching in Lisp

lisp (cond ((cond1) 'do-1a) ((cond2) 'do-2a 'do-2b) (t 'do-a 'do-b))

  • case - branching by matching with eq (so cannot branch on strings)

lisp (case var1 ((val1) 'do-1a 'do-1b) ((val2) 'do-2a) (otherwise 'do-a 'do-b))

  • conditionals - and and or - shortcut Boolean evaluation

  • comparisons

  • rule of thumb - use eq when comparing symbols and equal when comparing everything else.
  • eq - compares symbols only (also seems to compare ints and chars [case sensitive])
  • equal - general comparison (symbols, chars, numbers, strings [case insensitive], lists, etc)
  • eql - compares symbols, chars and numbers (but only of same type) - chars are case insensitive
  • equalp - like equal but can compare between different number types (e.g. float and int)
  • = - comparsion between number types
  • string-equal (case insensitive)
  • char-equal (case insensitive)

Chapter 4 (conditions)

Empty Equals False

The following are all false (scheme handles this differently)

  • ()
  • '()
  • nil
  • 'nil
(defun my-len (list)
    (if list
        (1+ (my-len (cdr list)))
        0))

if

only one branch executed, lisp will not evaluate the branch not taken

(if '(1)
    'this-is-true
    (/ 1 0))

Notes:

  • can only execute 1 item in each branch
  • (/ 1 0) will never be evaluated so lisp won't throw it out

when and unless

Executes multiple statements

(when (condition-is-true)
    'this-is-executed
    'and-so-is-this )
(unless (condition-is-false)
    'this-is-executed
    'and-so-is-this )

cond

Classic way to do branching in Lisp. Considered by some to be the one true Lisp conditional (as it's been around since the Lisp Stone Age)

(defvar *arch-enemy* nil)
(defun pudding-eater (person)
    (cond ((eq person 'henry)   (setf *arch-enemy* 'stupid-lisp-alien)
                                '(curse you lisp alien - you ate my pudding))
            ((eq person 'johnny)   (setf *arch-enemy* 'useless-old-johnny)
                                '(i hope you choked on my pudding johnny))
            (t      '(why you eatin' ma pudding stranger?))))

case

(defun pudding-eater (person)
    (case person
        ((henry)   (setf *arch-enemy* 'stupid-lisp-alien)
                    '(curse you lisp alien - you ate my pudding))
        ((johnny)   (setf *arch-enemy* 'useless-old-johnny)
                    '(i hope you choked on my pudding johnny))
        (otherwise  '(why you eatin' ma pudding stranger?))))

Note: case uses eq for comparison, so cannot be used to branch on string values.

conditionals "and" and "or"

> (and (oddp 5)(oddp 7)(oddp 9))
> (or (oddp 6)(oodp 4)(oddp 1))

Lisp will shortcut these statements (i.e. stop processing an or when it hits a true condition, stop processing an and condition when it hits a false). Handy for a trick like this...

(and *file-modified* (ask-user-about-saving) (save-file))

comparisons

  • eq - compares symbols only. (also seems to compare ints and chars as well)
  • eql - compares symbols, chars and numbers (but only of same type, e.g. int -> int, float -> float), chars are case insensitive
  • equal - general comparison (symbols, chars, numbers, strings [case sensitive], lists, etc)
  • equalp - like equal but can compare between number types (e.g. int -> float), strings are case insensitive
  • = - comparison between number types
  • string-equal - comparison between strings (case insensitive)
  • char-equal - comparison between chars (case insensitve)