From: Jeff Sandys
Subject: IF & AND redefined, why?
Date: 
Message-ID: <3ADCC6AE.BFE927BF@asme.org>
While working on some code, I found AND and IF redefined. 
I can't figure out why the programmer did it this way.

(defmacro myif (mytest mythen &optional myelse)
  `(let ((it ,mytest))
     (if it ,mythen ,myelse)))

(defmacro myand (&rest args)
  (cond ((null args) t)
        ((null (cdr args)) (car args))
        (t `(myif ,(car args) (myand ,@(cdr args))))))

Can anyone explain the difference between these and the 
regular AND and IF?  Would there be any difference in 
behavior if I substituted the regular AND and IF?

Thanks,
Jeff Sandys

From: Johann Hibschman
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <mty9szxg8n.fsf@astron.berkeley.edu>
Jeff Sandys writes:

> Can anyone explain the difference between these and the 
> regular AND and IF?  Would there be any difference in 
> behavior if I substituted the regular AND and IF?

Those versions bind the variable "it" to the result of the test.
If the code uses that variable, then, yes, you will have a problem
with it working.

An example of why the programmer probably wanted to do this would be

(myif (gethash h :name)     ; binds it = (gethash h :name)
  (format t "~A" it)        ; uses the value of it
  (format t "Key :name not found."))

A similar thing applies to the and variant.

--Johann

-- 
Johann Hibschman                           ······@physics.berkeley.edu
From: Johann Hibschman
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <mtu23nxg1j.fsf@astron.berkeley.edu>
Johann Hibschman writes:

> (myif (gethash h :name)     ; binds it = (gethash h :name)
>   (format t "~A" it)        ; uses the value of it
>   (format t "Key :name not found."))

Oops.  I have Scheme on my brain.  I'm sure you know what I meant,
even if this is broken.  No need to take out the thumbscrews.

--Johann

-- 
Johann Hibschman                           ······@physics.berkeley.edu
From: Christopher Stacy
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <u1yqqal3c.fsf@spacy.Boston.MA.US>
The programmer is binding a variable called IT to value of the test form,
and that variable is visible to the two then/else consequent clauses.
You would need to examine all the callers of the macro to see if the
variable IT is being used anywhere, and bind the variable for them.

If the program in question is supposed to be anything like normal 
Lisp code, I would recommend doing that and eliminating the weird
redefinitions of the normal IF and AND.
From: Ted Sandler
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <3ADD1851.FDADF98D@worldnet.att.net>
Jeff Sandys wrote:
> 
> While working on some code, I found AND and IF redefined.
> I can't figure out why the programmer did it this way.
> 
> (defmacro myif (mytest mythen &optional myelse)
>   `(let ((it ,mytest))
>      (if it ,mythen ,myelse)))

The author of this code is trying to use variable capture to avoid
recomputing the conditional clause of the "if statement".  Such a
technique could be useful if the result of the conditional clause was
computationally expensive and having to recompute it resulted in
inefficient code.

e.g.  the following code has to compute the function "calculate-answer"
twice:

(if (calculate-answer)
    (format t "The answer is ~A" (calculate-answer))
  (format t "There is no answer"))

The "myif" macro sought to avoid this by setting "it" to the result of
the conditional as in:

(myif (calculate-answer)
      (format t "The answer is ~A" it)
  (format t "There is no answer"))

Quite frankly, I think defining such a macro only serves to confuse
people.  Having to type out an extra "let" statement isn't going give
your friend RSI and it will give everyone the ablility to read and
understand the code clearly.


> (defmacro myand (&rest args)
>   (cond ((null args) t)
>         ((null (cdr args)) (car args))
>         (t `(myif ,(car args) (myand ,@(cdr args))))))

As for this "myand", I have no clue what's going on here...


> Can anyone explain the difference between these and the
> regular AND and IF?  Would there be any difference in
> behavior if I substituted the regular AND and IF?

Yes there's a difference, and unless you have good reason, avoid "myif"
and "myand" like the plague.

-- 
··········@att.net
From: Erik Naggum
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <3196581083601514@naggum.net>
* Ted Sandler <··········@worldnet.att.net>
> e.g.  the following code has to compute the function "calculate-answer"
> twice:
> 
> (if (calculate-answer)
>     (format t "The answer is ~A" (calculate-answer))
>   (format t "There is no answer"))
> 
> The "myif" macro sought to avoid this by setting "it" to the result of
> the conditional as in:
> 
> (myif (calculate-answer)
>       (format t "The answer is ~A" it)
>   (format t "There is no answer"))

  Programmers with slightly more experience would probably write this:

(format t "~:[There is no answer~;The answer is ~:*~A~]" (calculate-answer))

  Similar options are frequently available.

  Incidentally, you could name your anaphoric variable $_ or whatever Perl
  uses for the last value computed, and avoid the problem that it might
  look as if it were a tasteful thing to do.  "it" is not a reserved word,
  but it becomes one in myif and myand, and that's even worse than using a
  disgusting-looking Perlism.  If you really, really want anaphoric if and
  and, at least allow the programmer to choose the variable name, as in 

(iflet ((with-it (calculate-answer))
   (whatever with-it)
   (whatever-else)))

  Note: this is intentionally syntactically like a binding, so as not to
  confuse readers to believe that with-it is a function call.  This also
  makes it possible to roll this into a normal if.  (Provided precautions
  are taken against misinterpreting lamda forms, which are syntactically
  different from the binding form even in the one really pathological case.)

  And don't forget the functional style:

((lambda (x) (if x (whatever x) (whatever-else))) (calculate-answer))

#:Erik
-- 
  I found no peace in solitude.
  I found no chaos in catastrophe.
			-- :wumpscut:
From: Harald Hanche-Olsen
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <pcou23l3oi6.fsf@thoth.home>
+ Erik Naggum <····@naggum.net>:

|   Programmers with slightly more experience would probably write this:
| 
| (format t "~:[There is no answer~;The answer is ~:*~A~]" (calculate-answer))

Whereas programmers with slightly less experience, such as myself,
would more likely prefer

(let ((answer (calculate-answer)))
  (if answer
      (format t "The answer is ~A" answer)
    (format t "There is no answer")))

which is still an improvement over the original macro hack, and is
readable by mere mortals to boot.  8-)

(Rats.  I posted this with the logic reversed, but caught the mistake
right away and superseded the article.)
-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- Yes it works in practice - but does it work in theory?
From: Kent M Pitman
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <sfwae5674d6.fsf@world.std.com>
Harald Hanche-Olsen <······@math.ntnu.no> writes:

> + Erik Naggum <····@naggum.net>:
> 
> |   Programmers with slightly more experience would probably write this:
> | 
> | (format t "~:[There is no answer~;The answer is ~:*~A~]" (calculate-answer))

Stylistically, I prefer to write this:

(format t "~:[There is no answer~;~:*The answer is ~A~]" (calculate-answer))
 
so as to allow the arg backing up to be done at the first possible point in
case another ~A or ~S is introduced between the point of the ~; and the
point of the ~A, to avoid further confusion.

> Whereas programmers with slightly less experience, such as myself,
> would more likely prefer
> 
> (let ((answer (calculate-answer)))
>   (if answer
>       (format t "The answer is ~A" answer)
>     (format t "There is no answer")))
> 
> which is still an improvement over the original macro hack, and is
> readable by mere mortals to boot.  8-)

Well, while a newbie migth indeed have a rpeferred learning order, I 
recommend everyone at least use proper end of sentence punctuation
and proper newline breaking, which means getting ~% and ~& into use.
I recommend, for example,

 (format t "~&The answer is ~A.~%" answer)
and
 (format t "~&There is no answer.~%")

That is, always start a line of uncertain nature with a freshline, as a
guard against someone else having forgotten ~%, and always end with ~%
oout of politeness.  Further, always end a sentence with a period out of
proper grammar.

Then again, I suggest "No answer was computed." rather than 
"There is no answer.", as the latter sounds more like something you'd
get in response to (is-there-a-god?).  [Philosophical point.]

Btw, I don't think there's any good reason for "mere mortals" not to 
know about both ·@[...~], ~:[...~;...~], ~{...~}, and ~:{...~}.  These 
are far from obscure uses.  So anyone who doesn't know these should 
look into them at their earliest convenience.

And likewise the idiom ~:* is so often used that everyone should know it
as soon as possible.
From: Francis Leboutte
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <obrqdtcvfrjarugmdnskildp2d6bj3t4o0@4ax.com>
Ted Sandler <··········@worldnet.att.net> wrote:

>... Having to type out an extra "let" statement isn't going give
>your friend RSI and it will give everyone the ablility to read and
>understand the code clearly.

I often use an if-bind macro ,for example :

(if-bind (o (part-of node)) o node)

(defmacro if-bind ((var form) form1 form2)
  `(let ((,var ,form))
     (if ,var 
         ,form1
       ,form2)))


--
Francis Leboutte  www.algo.be  +32-(0)4.388.39.19
From: dave linenberg
Subject: Re: IF & AND redefined, why? (when-bind macro)
Date: 
Message-ID: <3ADD9F41.127593FA@nabny.com>
>
>    * Newsgroups: comp.lang.lisp
>    * From: Francis Leboutte <··········@algo.be>   wrote:
>
> I often use an if-bind macro ,for example :
>
> (if-bind (o (part-of node)) o node)
>
> (defmacro if-bind ((var form) form1 form2)
>   `(let ((,var ,form))
>      (if ,var
>          ,form1
>        ,form2)))

This works for single bindings, but what about for multiple bindings?
Inspired by Graham:

(defmacro when-bind-graham((var expr) &body body)
  `(let ((,var ,expr))
     (when ,var
       ,@body)))


I came up with the following (which I am sure can be critiqued as I consider myself a lisp newbie...) for parallel assignments,

(defmacro when-bind (lst &rest body)
  "when-bind binds (multiple) non-nil expressions to
   parallel inititiated variables.
   If the expression is nil, when-bind returns nil.
   Produces code in the following template
   (when-bind ((var1 expr1) (var2 expr2) ...(varN exprN))
          (form1)
          (form2)
          (formN))  is transformed to -->

   (let ((var1 expr1)
         (var2 expr2)
         (varN exprN))
     (when (and var1 var2 ... varN)
     (form1)
     (form2)
     (formN))) "

  (let* ((expr (mapcar #'car lst))
         (code `(LET ,lst (WHEN (AND ,@expr)))))
    (setf (third code)
          (nconc (third code) body))
    code))



And the following , when-bind*,  for sequential assignments:

(defun let-when-template (lst)
  "helper function for when-bind* macro"
  (destructuring-bind (var expr) lst
    `(let ((,var ,expr))
       (when ,var))))

(defmacro when-bind* (lst &rest body)
  "when-bind* binds (multiple) non-nil expressions to
   sequentially inititiated variables.
   If the expression is nil, when-bind* returns nil.
   Produces code in the following template
   (when-bind ((var1 expr1) (var2 expr2) ...(var-x expr-x))
          (form1)
          (form2)
              .
              .
          (form-n))  is transformed to -->

   (let ((var1 expr1))
      (when var1
        (let ((var2 expr2))
          (when var2
               .
               .
            (let ((var-x expr-x))
              (when var-x
                  (form1)
                  (form2)
                      .
                      .
                  (form-n)))))))"
  (let ((code (mapcar 'let-when-template lst)))
    (loop for el1 in code
          for el2 in (cdr code)
          do (setf (third el1) (nconc (third el1) (list el2)))
          finally (setf (third el2) (nconc (third el2) body)))
    (car code)))



-- 
Posted from [199.35.146.133] 
via Mailgate.ORG Server - http://www.Mailgate.ORG
From: Francis Leboutte
Subject: Re: IF & AND redefined, why? (when-bind macro)
Date: 
Message-ID: <9s5detshf3t2gnicoe7j1p7361kpmi6448@4ax.com>
··········@nabny.com (dave linenberg) wrote:

>I came up with the following (which I am sure can be critiqued as I consider 
>myself a lisp newbie...) for parallel assignments,
>
>(defmacro when-bind (lst &rest body)
>  "when-bind binds (multiple) non-nil expressions to
>   parallel inititiated variables.
>   If the expression is nil, when-bind returns nil.
>   Produces code in the following template
>   (when-bind ((var1 expr1) (var2 expr2) ...(varN exprN))
>          (form1)
>          (form2)
>          (formN))  is transformed to -->
> ...

maybe you are not going to use this often because it means the exprN expressions
are also evaluated for their side effects (they are always all evaluated even if
one of them is NIL).

>And the following , when-bind*,  for sequential assignments:
>...
>(defmacro when-bind* (lst &rest body)
>  "when-bind* binds (multiple) non-nil expressions to
>   sequentially inititiated variables.
>   If the expression is nil, when-bind* returns nil.
>   Produces code in the following template
>   (when-bind ((var1 expr1) (var2 expr2) ...(var-x expr-x))
>          (form1)
>          (form2)
>          (form-n))  is transformed to -->
> ...

This one should be useful. As soon as an exprN expression is NIL, the macro
returns NIL.

The when-bind (or if-bind) I use is bit more elaborated that the one I post some
days ago; it allows me to write :

(let ((val -1))
   (when-bind (v val #'integerp #'oddp #'minusp)
     (format nil "~D" val)))
=> "-1"

(let ((val 1))
   (when-bind (v val #'integerp #'oddp #'minusp)
     (format nil "~D" val)))
=> NIL

;;; function intersection. See On Lisp
(defun fint (fn &rest fns)
  (if (null fns)
      fn
      (let ((chain (apply #'fint fns)))
        (lambda (x) 
          (and (funcall fn x) (funcall chain x))))))


(defmacro when-bind ((var form &rest predicates) &body body)
   `(let ((,var ,form))
       ,(if (consp predicates)
           `(if (and ,var (funcall (fint ,@predicates) ,var))
               (progn ,@body)
               NIL)
           `(if ,var 
               (progn ,@body)
               NIL))))
--
www.algo.be
Logo programming : www.algo.be/logo.html
From: Dr. Edmund Weitz
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <3add2aa2.490105975@news.cis.dfn.de>
I just wanted to add that the technique used here is what Paul Graham
(in 'On Lisp') calls 'anaphoric macros'. If my memory serves me right,
there's a whole chapter about this technique.

So, I think the guy who wrote the orginal code has been bashed enough.
I think he new what he did and he was just doing something that (under
certain circumstances, of course) is recommended in a book that almost
everybody seems to love.

Cheers,
Edi.

--
Dr. Edmund Weitz
Hamburg
Germany
http://www.weitz.de/
From: Stig Hemmer
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <ekv1yqqgm6a.fsf@proto.pvv.ntnu.no>
···@agharta.de (Dr. Edmund Weitz) writes:
> I just wanted to add that the technique used here is what Paul Graham
> (in 'On Lisp') calls 'anaphoric macros'. If my memory serves me right,
> there's a whole chapter about this technique.
> 
> So, I think the guy who wrote the orginal code has been bashed enough.
> I think he new what he did and he was just doing something that (under
> certain circumstances, of course) is recommended in a book that almost
> everybody seems to love.

"On Lisp" tells the reader an aweful lot about what you _can_ do with
macros, but is rather silent on what you _should_ do with macros.

I loved the book for its sheer "Wow!" power as it made me reallize how
much power there is in Lisp-style macros.  Some of his macros gives me
a trill.  It is like a power tool, just begging to be used.

On the other hand, the code in the book is _not_ what I would call
good style.  It is downright obfuscated at times.

For good style I would recommend Peter Norvigs book, "Paradigms of AI
Programming: Case Studies in Common Lisp".  In this book Norvig
tackles some serious problems and shows you how to solve them.  And
the code he writes is just beautiful.  Very understandable.  Nobody
should be afraid that this book is too hard for them, reading it will
be good for your soul, even if you don't understand everything. :-)

Stig Hemmer,
Jack of a Few Trades.
From: Erik Naggum
Subject: Re: IF & AND redefined, why?
Date: 
Message-ID: <3196623881130618@naggum.net>
* Dr. Edmund Weitz
> I just wanted to add that the technique used here is what Paul Graham
> (in 'On Lisp') calls 'anaphoric macros'. If my memory serves me right,
> there's a whole chapter about this technique.

  Let us improve on it, not accept it as gospel.  I suggest, for instance,
  that we expose the bindings of the anaphoric variables, instead of using
  a "magic" variable whose binding is neither visible not changeable.

> So, I think the guy who wrote the orginal code has been bashed enough.
> I think he new what he did and he was just doing something that (under
> certain circumstances, of course) is recommended in a book that almost
> everybody seems to love.

  It is one of few books on Common Lisp, it is fairly recent, and it has a
  lot of merit to it, but I am not sure it is a "here are the facts" kind
  of book, nor "this is how you do it", but rather "this is what I do, and
  I think it's great".  Mistaking it for any of the other types of book is
  going to hurt people.  I highly value Paul Graham's insights and opinions
  and wouldn't want to be without them, _but_ I also think any reader of
  such a book should be a good student and question his master.  Go not
  where he went, find out why he went where he did.  Chances are the
  destination is an accident of circumstances, but his choices were not.

#:Erik
-- 
  I found no peace in solitude.
  I found no chaos in catastrophe.
			-- :wumpscut: