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
andor
- shortcut Boolean evaluation -
comparisons
- rule of thumb - use
eq
when comparing symbols andequal
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 insensitiveequalp
- likeequal
but can compare between different number types (e.g. float and int)=
- comparsion between number typesstring-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)