2

I'm reading The Little Schemer. And thanks to my broken English, I was confused by this paragraph:

(cond ... ) also has the property of not considering all of its arguments. Because of this property, however, neither (and ... ) nor (or ... ) can be defined as functions in terms of (cond ... ), though both (and ... ) and (or ... ) can be expressed as abbreviations of (cond ... )-expressions:

(and a b) = (cond (a b) (else #f) 
    and 
(or a b) = (cond (a #t) (else (b))

If I understand it correctly, it says (and ...) and (or ...) can be replaced by a (cond ...) expression, but cannot be defined as a function that contains (cond ...). Why is it so? Does it have anything to do with the variant arguments? Thanks.

p.s. I did some searching but only found that (cond ...) ignores the expressions when one of its conditions evaluate to #f.

babel92
  • 767
  • 1
  • 11
  • 21
  • 1
    In addition to the answers that you get here, you might look at the answers to [Why (apply and '(1 2 3)) doesn't work while (and 1 2 3) works in R5RS?](http://stackoverflow.com/q/17232240/1281433) and [Using AND with the apply function in Scheme](http://stackoverflow.com/questions/387775/using-and-with-the-apply-function-in-scheme). The topic of the questions is a little different than your question, but the answers explain some of the same concepts. – Joshua Taylor Oct 14 '13 at 16:47
  • Thank you! The two posts are quite enlightening. Now I think I need to read the SICP. – babel92 Oct 14 '13 at 20:30
  • It's well worth the read, and it's [available for free online](http://mitpress.mit.edu/sicp/full-text/book/book.html). – Joshua Taylor Oct 14 '13 at 20:30

2 Answers2

7

Imagine you wrote if as a function/procedure rather than a user defined macro/syntax:

;; makes if in terms of cond
(define (my-if predicate consequent alternative)
  (cond (predicate consequent)
        (else alternative)))

;; example that works
(define (atom? x)
  (my-if (not (pair? x))
         #t
         #f))

;; example that won't work
;; peano arithemtic
(define (add a b)
  (my-if (zero? a)
         b
         (add (- a 1) (+ b 1))))

The problem with my-if is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom? the parts (not (pair? x)), #t and #f were evaluated before the body of my-if gets executed.

For the last example means (add (- a 1) (+ b 1)) gets evaluated regardless of what a is, even when a is zero, so the procedure will never end.

You can make your own if with syntax:

(define-syntax my-if
  (syntax-rules ()
    ((my-if predicate consequent alternative)
     (cond (predicate consequent)
           (else alternative)))))

Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It's replaced with the other just reusing the expressions so that:

(my-if (check-something) (display 10) (display 20))

would be replaced with this:

(cond ((check-something) (display 10))
      (else (display 20)))

With the procedure version of my-if both 10 and 20 would have been printed. This is how and and or is implemented as well.

Sylwester
  • 47,942
  • 4
  • 47
  • 79
1

You cannot define cond or and or or or if as functions because functions evaluate all their arguments. (You could define some of them as macros).

Read also the famous SICP and Lisp In Small Pieces (original in French).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547