Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there non-lazily evaluated "and" or "or" operations in Common Lisp?

The usual and and or operators in Common Lisp will lazily evaluate their operands, e.g. the and will stop once it encounters the first nil. I am searching for an operator that does not work this way, but instead always evaluates all operands before returning a result. Is there something like this?

In C for example you have the lazy && and you have the bitwise &, which can be used as a non-lazy alternative. I know about logand and bit-and, but those do not work on boolean operands.

E.g.:

(and NIL (not-defined))

would not throw an error, but i want it to throw one.

like image 929
Tim Avatar asked Aug 13 '19 12:08

Tim


People also ask

Does lisp have lazy evaluation?

Lisp also has several built-in forms which have different evaluation rules. IF is such an example. In Common Lisp IF is a so-called special operator. But we can define a new Lisp-like (sub-) language which uses lazy evaluation and we can write Macros to transform that language into Lisp.

Does C use lazy evaluation?

Yes, in C++ short circuit and and or operators are available. Here's a question answered in the C-faq on the subject. Show activity on this post. It's definitely the case in both C and C++.


2 Answers

(defun and* (&rest l)
  (every #'identity l))

or returning the last value if all true

(defun and& (&rest l)
  (or (null l)
      (loop for b in l
            unless b
              do (return nil)
            finally (return b))))

or

(defun and& (&rest l)
  (or (null l)
      (loop for b in l
            always b
            finally (return b))))
like image 182
Rainer Joswig Avatar answered Sep 19 '22 01:09

Rainer Joswig


A possible implementation is

(defun and* (&rest x)
  (let ((res T))
    (dolist (item x)
      (if (null item) (return-from and* item))
      (setf res item))
    res))

Explanation:

  • We initialize the result to T (this is needed because (and)T)
  • We loop over the arguments
  • If an argument is NIL then we return it
  • Otherwise we store the item as result
  • If we get to the end of the loop then we return last item

The implementation of or* is simpler because the only "falsy" value in Common Lisp is NIL so there's no need to remember what is the last falsy element and you can just use some...

(defun or* (&rest x)
  (some #'identity x))
like image 29
6502 Avatar answered Sep 21 '22 01:09

6502