**if**expression in newLISP can usually be found to have different semantics than

**if**s in other lisps. Lutz has chosen for it to have semantics which are in the spirit of

**cond**.

I believe that this is a great choice, because newLISP's

**if**is a general type of

**if**. What do I mean by this? In the manual discussion, we are presented with the two different forms of

**if**; but in fact, the second form (the one that takes an arbitrary number of clauses) is just a generalization of the first form.[1]

Lutz may not like for me to say this, but

*there is a beauty and a consistency*[2] in its simple semantics. (Programming language geeks like me love it, but I think other users would too. This is something that I think can bring us all together. :)

I believe that Lutz made a great decision in choosing the semantics of newLISP's

**if**expression, and in the following, I am going to detail why this is so.

The arguments to

**if**are a list of clauses, which in the non-degenerate cases, are pairs of

*test and consequent clauses*. The situation looks like this:

(

**if**

*test-clause-1*

*consequent-clause-1*. . .

*test-clause-N*

*consequent-clause-N*)

These pairs are continually looped though until the first such test clause evaluates to a "truthy" value, in which case its corresponding consequent clause is evaluated and yielded as the value of the

**if**expression itself.

The degenerate cases are when the

**if**expression has one clause (argument) or none. But these cases can be thought of as base cases of a recursive evaluator for

**if**. In fact, you can write such an evaluator in newLISP. Here is one.

Code: Select all

```
(define (eval-if EXPR)
(if (empty? EXPR) nil
(= 'if (EXPR 0)) (eval-if (1 EXPR))
(= 1 (length EXPR)) (eval (EXPR 0))
(let (test-clause (EXPR 0)
consequent-clause (EXPR 1)
rest-of-the-clauses (2 EXPR))
(if (eval test-clause)
(eval consequent-clause)
(eval-if rest-of-the-clauses)))))
```

**if**

*in newLISP itself!!!*Yeah, that's cool.

Now, it is clear why the degenerate cases yield the values they do for newLISP's

**if**. Here are some examples of these cases.

Code: Select all

```
(if) ;=> nil
(if 42) ;=> 42
(if (+ 2 40)) ;=> 42
```

Code: Select all

```
(eval-if '(if)) ;=> nil
(eval-if '(if 42)) ;=> 42
(eval-if '(if (+ 2 40))) ;=> 42
```

**if**in the manual look like this.

Code: Select all

```
(set 'x 50)
(if (< x 100) "small" "big") ;=> "small"
(set 'x 1000)
(if (< x 100) "small" "big") ;=> "big"
(if (> x 2000) "big") ;=> nil
```

Code: Select all

```
(set 'x 50)
(eval-if '(if (< x 100) "small" "big")) ;=> "small"
(set 'x 1000)
(eval-if '(if (< x 100) "small" "big")) ;=> "big"
(eval-if '(if (> x 2000) "big")) ;=> nil
```

**if**in the manual.

Code: Select all

```
(define (classify x)
(if (< x 0) "negative"
(< x 10) "small"
(< x 20) "medium"
(>= x 30) "big"
"n/a"))
(classify 15) ;=> "medium"
(classify 100) ;=> "big"
(classify 22) ;=> "n/a"
(classify -10) ;=> "negative"
```

Code: Select all

```
(define (classify-eval-if x)
(eval-if '(if (< x 0) "negative"
(< x 10) "small"
(< x 20) "medium"
(>= x 30) "big"
"n/a")))
(classify-eval-if 15) ;=> "medium"
(classify-eval-if 100) ;=> "big"
(classify-eval-if 22) ;=> "n/a"
(classify-eval-if -10) ;=> "negative"
```

[1] No doubt though that the manual presents two forms of

**if**to the user because the first form is well-known; so it will communicate its ideas (about it and the second form) best to the broadest section of readers.

[2] There you go, Lutz; I used

*both*terms. :)