The semantics of newLISP's if

Started by rickyboy, August 16, 2013, 12:23:48 PM

Previous topic - Next topic

rickyboy

The if expression in newLISP can usually be found to have different semantics than ifs 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 http://www.newlisp.org/downloads/newlisp_manual.html#if">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]



http://www.newlispfanclub.alh.net/forum/viewtopic.php?t=4381&p=21628#p21628">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 http://docs.nodejitsu.com/articles/javascript-conventions/what-are-truthy-and-falsy-values">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.


(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)))))

There is something important lurking here, and it is that this function describes the semantics of newLISP's 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.


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

Our evaluator treats them the same.


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

Next, examples from the first form of if in the manual look like this.


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

Our evaluator in action now.


(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

Finally, the examples from the second form of if in the manual.


(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"

Our evaluator.


(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. :)
(λx. x x) (λx. x x)

Lutz

#1
Quote[2] There you go, Lutz; I used both terms. :)


Sigh of relief. You will get promoted from rickyboy to rickman :)