skip to Main Content

I am reading the book Paradigms of Artificial Intelligence Programming : Case studies in Common LISP by Peter Norvig, and in the chapter about the special forms for conditionals it says that they all can be replaced by the if form

(when test a b c) == (if test (progn a b c)) 
(unless test x y) == (if (not test) (progn x y) 
(and a b c) == (if a (if b c)) 
(or a b c) == (if a a (if b b c)) 
(case a (b c) (t  x)) == (if (eql a 'b) c x) 

I don’t understant how that works, could anyone explain it to me? What about the cond form, can it also be replaced by the if form? Can I then create a macro-function with the if form to replace when, unless, and, etc…?

3

Answers


  1. IF is a general purpose conditional that chooses from two branches depending on a single condition. All those others are just easier ways to write it when there are more than two branches (AND, OR, CASE) or only one branch (WHEN, UNLESS).

    COND can also be done with IF, for example:

    (eval-when (:compile-toplevel :load-toplevel :execute)
      (defun ifify-clauses (clauses)
        (when clauses
          (destructuring-bind (condition form) (first clauses)
            `(if ,condition ,form ,(ifify-clauses (rest clauses)))))))
    
    (defmacro if-cond (&body clauses)
      (ifify-clauses clauses))
    
    (macroexpand '(if-cond
                    ((= 3 1) "foo")
                    ((= 3 2) "bar")
                    ((= 3 3) "quux")))
    ;=> (IF (= 3 1)
    ;       "foo"
    ;       (IF (= 3 2)
    ;           "bar"
    ;           (IF (= 3 3)
    ;               "quux"
    ;               NIL)))
    
    Login or Signup to reply.
  2. It’s not only possible but it’s exactly what happens when you use cond:

    (macroexpand '(cond ((< v 0) (print "negative") (* -2 v))
                        ((> v 0) (print "positive") (1- (* 2 v)))
                        (t (print "zero") 0)))
    ; ==>
    (if (< v 0) 
        (progn (print "negative") 
               (* -2 v))
        (if (> v 0)
            (progn (print "positive") 
                   (1- (* 2 v)))
            (progn (print "zero")
                   0))) 
    

    So when you use cond in CL it replaces it with the equivalent if form at the macro expansion stage. That happens usually once for each place the macro is used in a program.

    Usually the core language does not support many ways to do the same so I guess everything will be transformed to if unless the implementation found a reason to keep it primitive.

    The CLHS reflects this by the title of the forms as “Special Operator IF” and “Macro COND“.

    You can define your own macros that do conditionals and you are free to choose of the already available conditionals to replace it with since the macros are expanded until there are no more left. Here is a definition of an anaphoric if:

    (defmacro aif (p a &optional c)
      `(let ((it ,p))
         (if it ,a ,c)))
    
    (macroexpand '(aif (extremely-expensive-function x)
                       (use-value it)
                       (compute-other-result)))
    ; ==>
    (let ((it (extremely-expensive-function x)))
      (if it
          (use-value it)
          (compute-other-result)))
    
    Login or Signup to reply.
  3. You are on page 53 of PoAIP. If you go on reading this page and the next ones, the explanation follows.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search