is it possible to write a strict AND function?

Discussion of Common Lisp
yesimthetaxman
Posts: 10
Joined: Thu Jul 07, 2011 7:02 pm

is it possible to write a strict AND function?

Post by yesimthetaxman » Thu Jul 07, 2011 7:22 pm

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...

wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

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

Post by wvxvw » Thu Jul 07, 2011 11:10 pm

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
Last edited by wvxvw on Thu Jul 07, 2011 11:33 pm, edited 2 times in total.

smithzv
Posts: 94
Joined: Wed Jul 23, 2008 11:36 am

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

Post by smithzv » Thu Jul 07, 2011 11:16 pm

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.

Paul
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

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

Post by Paul » Fri Jul 08, 2011 6:35 am

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

gugamilare
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil
Contact:

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

Post by gugamilare » Fri Jul 08, 2011 10:36 am

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.

wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

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

Post by wvxvw » Fri Jul 08, 2011 1:23 pm

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.

Paul
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

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

Post by Paul » Fri Jul 08, 2011 4:50 pm

Multi-arg version is just

Code: Select all

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

wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

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

Post by wvxvw » Fri Jul 08, 2011 11:59 pm

Oh, right, I for whatever reason imagined that the first argument is mandatory.

gugamilare
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil
Contact:

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

Post by gugamilare » Sat Jul 09, 2011 10:26 am

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

wvxvw
Posts: 127
Joined: Sat Mar 26, 2011 6:23 am

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

Post by wvxvw » Sun Jul 10, 2011 1:37 am

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

Post Reply