1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
<HTML>
<HEAD>
<TITLE>Common LISP Hints: Booleans and Conditionals</TITLE>
</HEAD>
<BODY>
<A HREF="LISP-tutorial-16.html"><IMG SRC="prev.gif" ALT="Previous"></A>
<A HREF="LISP-tutorial-18.html"><IMG SRC="next.gif" ALT="Next"></A>
<A HREF="LISP-tutorial.html#toc17"><IMG SRC="toc.gif" ALT="Contents"></A>
<HR>
<H2><A NAME="s17">17. Booleans and Conditionals</A></H2>
<P>LISP uses the self-evaluating symbol <CODE>nil</CODE> to mean false. Anything other
than <CODE>nil</CODE> means true. Unless we have a reason not to, we usually use the
self-evaluating symbol <CODE>t</CODE> to stand for true.</P>
<P>LISP provides a standard set of logical functions, for example
<CODE>and</CODE>, <CODE>or</CODE>,
and <CODE>not</CODE>. The <CODE>and</CODE> and <CODE>or</CODE> connectives are
short-circuiting: and will not
evaluate any arguments to the right of the first one which evaluates to
<CODE>nil</CODE>, while <CODE>or</CODE> will not evaluate any arguments to the right
of the first
one which evaluates to <CODE>t</CODE> (with <CODE>t</CODE> we mean here ``non-<CODE>nil</CODE>'').</P>
<P>LISP also provides several special forms for conditional execution. The
simplest of these is <CODE>if</CODE>. The first argument of <CODE>if</CODE> determines whether
the second or third argument will be executed:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
> (if t 5 6)
5
> (if nil 5 6)
6
> (if 4 5 6)
5
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>If you need to put more than one statement in the then or else clause
of an if statement, you can use the <CODE>progn</CODE> special
form. <CODE>Progn</CODE> executes
each statement in its body, then returns the value of the final one.</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
> (setq a 7)
7
> (setq b 0)
0
> (setq c 5)
5
> (if (> a 5)
(progn
(setq a (+ b 7))
(setq b (+ c 8)))
(setq b 4))
13
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>An <CODE>if</CODE> statement which lacks either a then or an else clause can be
written using the <CODE>when</CODE> or <CODE>unless</CODE> special form:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
> (when t 3)
3
> (when nil 3)
NIL
> (unless t 3)
NIL
> (unless nil 3)
3
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P><CODE>When</CODE> and <CODE>unless</CODE>, unlike <CODE>if</CODE>, allow any number of
statements in their
bodies. (Eg, <CODE>(when x a b c)</CODE> is equivalent to
<CODE>(if x (progn a b c))</CODE>.)</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
> (when t
(setq a 5)
(+ a 6))
11
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>More complicated conditionals can be defined using the <CODE>cond</CODE> special
form, which is equivalent to an if ... else if ... fi construction.</P>
<P>A <CODE>cond</CODE> consists of the symbol <CODE>cond</CODE> followed by a number of cond
clauses, each of which is a list. The first element of a cond clause is
the condition; the remaining elements (if any) are the action. The cond
form finds the first clause whose condition evaluates to true (ie,
doesn't evaluate to nil); it then executes the corresponding action and
returns the resulting value. None of the remaining conditions are
evaluated; nor are any actions except the one corresponding to the
selected condition. For example:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
> (setq a 3)
3
> (cond
((evenp a) a) ;if a is even return a
((> a 7) (/ a 2)) ;else if a is bigger than 7 return a/2
((< a 5) (- a 1)) ;else if a is smaller than 5 return a-1
(t 17)) ;else return 17
2
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>If the action in the selected cond clause is missing, <CODE>cond</CODE> returns what
the condition evaluated to:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
> (cond ((+ 3 4)))
7
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Here's a clever little recursive function which uses <CODE>cond</CODE>. You might be
interested in trying to prove that it terminates for all integers <CODE>x</CODE> at
least 1. (If you succeed, please publish the result.)</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
> (defun hotpo (x steps) ;hotpo stands for Half Or Triple Plus One
(cond
((= x 1) steps)
((oddp x) (hotpo (+ 1 (* x 3)) (+ 1 steps)))
(t (hotpo (/ x 2) (+ 1 steps)))))
A
> (hotpo 7 0)
16
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>The LISP case statement is like a C switch statement:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
> (setq x 'b)
B
> (case x
(a 5)
((d e) 7)
((b f) 3)
(otherwise 9))
3
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>The otherwise clause at the end means that if <CODE>x</CODE> is not <CODE>a</CODE>,
<CODE>b</CODE>, <CODE>d</CODE>, <CODE>e</CODE>, or <CODE>f</CODE>, the case statement will return 9.</P>
<HR>
<A HREF="LISP-tutorial-16.html"><IMG SRC="prev.gif" ALT="Previous"></A>
<A HREF="LISP-tutorial-18.html"><IMG SRC="next.gif" ALT="Next"></A>
<A HREF="LISP-tutorial.html#toc17"><IMG SRC="toc.gif" ALT="Contents"></A>
</BODY>
</HTML>
|