Page 1 of 2

is it possible to write a strict AND function?

Posted: Thu Jul 07, 2011 7:22 pm
by yesimthetaxman
I am trying to write a simple boolean AND function that uses eager/strict evaluation. That is, I want both arguments to the AND function to be evaluated. I am able to write a function to simulate this using IF statements, but it is long, I am wondering if anyone has any ideas how to write a shorter, more elegant version that evaluates the two arguements and then AND's them...

Re: is it possible to write a strict AND function?

Posted: Thu Jul 07, 2011 11:10 pm
by wvxvw
Let's see if it helps, I'm not exactly sure where do you want to evaluate arguments, but I assumed that you didn't want to continue checking the arguments after you are sure about the result:

Code: Select all

(defun hungry-and (x &rest y)
  (format t "arguments: ~a~&" x) ; but the function will stop checking them
  ; once it sees first argument that evaluates to nil
  (when x (when y (apply 'hungry-and y))))

(hungry-and :foo :bar 42 t nil "string") ; arguments are evaluated here

Re: is it possible to write a strict AND function?

Posted: Thu Jul 07, 2011 11:16 pm
by smithzv
Yeah, remember that for functions, all arguments will be evaluated prior to calling the function. This doesn't happen with AND because it is a macro (or special form).

This is kind of a FAQ and the common answer is to look at the EVERY function for AND and the SOME function for OR. You can also do this simply enough using REDUCE, or build your own function like...

Code: Select all

(defun my-and (&rest args)
  (cond ((not args)
         ;; There are no arguments, default to true
         t )
        (t (and (car args) (apply #'my-and (cdr args)))) ))
Note, we still use AND, it will still short circuit the recursion, but all of the arguments are evaluated before we ever call MY-AND.

Re: is it possible to write a strict AND function?

Posted: Fri Jul 08, 2011 6:35 am
by Paul
yesimthetaxman wrote:I am trying to write a simple boolean AND function that uses eager/strict evaluation. That is, I want both arguments to the AND function to be evaluated. I am able to write a function to simulate this using IF statements, but it is long, I am wondering if anyone has any ideas how to write a shorter, more elegant version that evaluates the two arguements and then AND's them...
If you just want a two-argument version:

Code: Select all

(defun my-and (x y) (and x y))

Re: is it possible to write a strict AND function?

Posted: Fri Jul 08, 2011 10:36 am
by gugamilare
wvxvw wrote:Let's see if it helps, I'm not exactly sure where do you want to evaluate arguments, but I assumed that you didn't want to continue checking the arguments after you are sure about the result:

Code: Select all

(defun hungry-and (x &rest y)
  (format t "arguments: ~a~&" x) ; but the function will stop checking them
  ; once it sees first argument that evaluates to nil
  (when x (when y (apply 'hungry-and y))))

(hungry-and :foo :bar 42 t nil "string") ; arguments are evaluated here
I didn't test it, but it seems your code is a bit wrong because it will always return nil. For instance, with only one argument, when X is true, it will see that Y is empty and return nil.

Re: is it possible to write a strict AND function?

Posted: Fri Jul 08, 2011 1:23 pm
by wvxvw
Oh, sorry, it wasn't just a bit wrong, it was a whole lot wrong :) Well...

Code: Select all

(defun hungry-and (x &rest y)
  (format t "arguments: ~a~&" x) ; but the function will stop checking them
  ; once it sees first argument that evaluates to nil
  (when x (every 'or y)))
A fixed version. Although, I must note that smithzv would also be wrong when called with empty list for example.

Re: is it possible to write a strict AND function?

Posted: Fri Jul 08, 2011 4:50 pm
by Paul
Multi-arg version is just

Code: Select all

(defun hungry-and (&rest args) (every #'identity args))

Re: is it possible to write a strict AND function?

Posted: Fri Jul 08, 2011 11:59 pm
by wvxvw
Oh, right, I for whatever reason imagined that the first argument is mandatory.

Re: is it possible to write a strict AND function?

Posted: Sat Jul 09, 2011 10:26 am
by gugamilare
wvxvw wrote:Oh, sorry, it wasn't just a bit wrong, it was a whole lot wrong :) Well...

Code: Select all

(defun hungry-and (x &rest y)
  (format t "arguments: ~a~&" x) ; but the function will stop checking them
  ; once it sees first argument that evaluates to nil
  (when x (every 'or y)))
A fixed version. Although, I must note that smithzv would also be wrong when called with empty list for example.
That won't work either, or is not a function.
Calling (and) returns t, so (hungry-and) should also return t.


One might want a compiler macro of hungry-and:

Code: Select all

(define-compiler-macro hungry-and (&rest args)
  (let ((syms (loop repeat (length args) collect (gensym))))
    `(let ,(mapcar #'list syms args)
         (and ,@syms))))
(I just have a bad feeling about constructing a list at run time when that is not necessary :P).

Re: is it possible to write a strict AND function?

Posted: Sun Jul 10, 2011 1:37 am
by wvxvw
Even though 'or isn't a function you are allowed to use it with 'every, so it will work as advertised (at least it worked for me in SBCL and CLISP). :) except for, as you quite righteously noted it won't work for empty list (and I did say I thought that the original 'and must take at least one argument). So, that is, of course my mistake. And well, OP wanted a function...
As an aside, I don't quite understand why is original 'and returns true if given no arguments, or why is there such an option at all. (That's to say I don't understand, not that it's wrong).