------------------------------------------------------------------------------
MC logo
Tom's Lisp Conditional Operators
[^] Tom's Lisp
------------------------------------------------------------------------------
[Basic Input Format] [Lists, Pairs and Related Operations] [Conditional Evaluation] [Basic Function Definition] [Definitions and Scope] [Functions Which Take Functions] [String Functions] [Exception Handling] [Quoting And Evaluation] [Variable-Length Parameter Lists] [Macro Definitions] [Printing] [The Tomslsp command and its switches] [Index of Standard Functions]

Lisp is a functional language, meaning that everything is done by function evaluation. Since there are no statements, there can be no if statement; conditional execution is managed with functions. This is not really as strange as it seems; the C/C++/Java ?: expression is similar.

The If Function

The simplest Tom's Lisp conditional is the if, which takes the form
(if condition thenexpression [ elseexpression ] )
The condition is evaluated. If it produces a true value, then thenexpression is evaluated to give the value of the whole if expression. Otherwise, elseexpression is evaluated and returned. If elseexpression is omitted and condition is false, the if returns nil.

Ordinary Tom's Lisp functions evaluate all their arguments before running the function. The if form, like cond described below, is not ordinary. Much as the if statement in a procedural language, Tom's Lisp evaluates just the condition first, then uses the result to decide which branch to evaluate. The one not chosen is left unevaluated.

Comparisons and Boolean Operations

The C language does not have a boolean type, but uses integer to do the job, letting zero be false and other values be true. Tom's Lisp, following other Lisps, takes a similar approach using lists. The empty list serves as false and all other values are true. Both nil and #f are identifiers defined by the system to evaluate to the empty list, so they can serve as false in most circumstances. The atom #t is defined to evaluate to itself as a convenient true. Note that the integer zero is not the empty list, so treated as true.
lsp>#f
nil
lsp>#t
#t
lsp>(< 5 8)
#t
lsp>(if (< 5 8) 12 19)
12
lsp>(if (>= 4 11) "Snake" "Eeel")
"Eeel"
lsp>(if 'moose 'owl 'turkey)
owl
lsp>(if (< 5 3) (/ 3 0) (+ 6 7))
13
The last case demonstrates that the division was not evaluated, since that would have produced an error.

There are several operators which return true or false values which can be used in testing. These sorts of functions are called predicates. These include the comparisons which operate on pairs of integers: <, >, <=, >=, = and !=, whose meaning is straightforward. There is also a group of type identifiers which tell if their single argument is a particular type of data:
null?Tell if the argument is nil (empty list).
pair?Tell if the argument is a pair (result of cons, most often a non-empty list.)
id?Tells if the argument is an identifier.
int?Tells if the argument is an integer.
str?Tells if the argument is a string.
builtin?Tells if the argument is a builtin function.
lambda?Tells if the argument is a function (result of the lambda operator).
macro?Tells if the argument is a macro (result of the macro operator).
functional?Tells if the argument is something that can be called with a parameter list as a function is. These are any of the last three types.

lsp>(null? '(a b c))
nil
lsp>(null? ()) 
#t
lsp>(null? 'a)
nil
lsp>(id? 'fred)
#t
lsp>(id? 17)
nil
lsp>(int? 17)
#t
lsp>(builtin? car)
#t
lsp>(functional? 17)
nil

A widely-used predicate is equal?, which tells if any two arguments of any type are the same. It is more general than =, which only operates on integers.

lsp>(equal? 'fred 'alice)
nil
lsp>(equal? '(fred alice mike) '(fred alice mike))
#t
lsp>(equal? '(fred alice mike) '(fred (alice mike)))
nil
lsp>(equal? 'fred "fred")
nil
lsp>(equal? 'joe 'joe)
#t
lsp>(equal? (cons 17 '(4 19)) (cdr '(3 17 4 19)))
#t

Finally, there is the eq? predicate. It compares the internal pointers, so it tells if the two data items are represented by the same internal object. It is included only because most Lisps have one.

lsp>(eq? nil nil)
#t
lsp>(eq? 'a 'a)
nil
lsp>(eq? '(a b c) '(a b c))
nil
lsp>(eq? 5 5)
nil
lsp>(eq? car car)
#t
The behavior of eq? in any particular Lisp depends on the implementation. In Tom's Lisp, eq? usually returns false, except when a stored value is compared to itself.

Once we have have comparisons and predicates to generate boolean values, it's also nice to have some boolean combinations. Tom's Lisp provides not which inverts its argument and returns #t or nil. It also provides or, and, nand and nor, which are short-circuit and take any number of arguments. The or operator returns the first argument which is not nil, or nil. The others always return #t or nil.

lsp>(and (< 5 34) (equal? '(a . b) (cons 'a 'b)) (builtin? cons))
#t
lsp>(not 19)
nil
lsp>(or () (+ 4 5) (< 5 6))
9

The Cond Operator

The other standard conditional construct is happily known as cond. It is similar to the case or switch in other languages, but with more general conditions. It takes the form:
(cond (c1 v1) . . . (cn vn))
The system evaluates c1. If it is true, v1 is evaluated and returned. Otherwise, the system goes on to c2. It returns the vi for the first ci which evaluates to true. If no condition is true, the form returns nil. Frequently the last condition, cn, is #t to assure that vn will be evaluated, if nothing else is. This operates much like the default label in a C/C++/Java switch.
lsp>(cond ((< 5 6) 'first) ((> 5 6) 'second) (#t 'third)))
first
lsp>(cond ((< 7 6) 'first) ((> 7 6) 'second) (#t 'third)))
second
lsp>(cons 'a (cond ((< 4 6) '(g l u)) ((> 4 6) '(w e))))
(a g l u)

The Begin Operator

The begin operator takes any number of forms expressions, evaluates them left to right, and returns the value of the last one. It is useful when you need to combine several operations into the branch of an if. Tomslisp begin is much like begin/end in Pascal and similar languages, or curly braces in C and friends.
lsp>(begin (* 4 5) (+ 3 4) (/ 7 5))
1
lsp>(if (< 4 5) (begin (* 4 5) (+ 3 4) (/ 7 5)) 45)
1