Compare multiple items

So, I want to compare four different items from four different lists. Something like the example below, the problem is that equal should only take 2 arguments, is there any function to compare more than two elements?

(equal (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)))

      

+3


source to share


2 answers


is there any function for comparing more than two items?

Many of the comparison functions in Common Lisp take more than two arguments. For example, all =, / =, <,>, <=,> = take any number of arguments, which means you can do

(= (nth 0 '(1 2 3))
   (nth 0 '(1 2 3))
   (nth 0 '(1 2 3))
   (nth 0 '(1 2 3)))

      

If you require the specific behavior of equal (rather than = ), then you will need the coredump approach suggested . Since equality is transitive, you can check that each element is equal for the first element (or that the list is empty):

(defun equal* (&rest arguments)
  (or (endp arguments)
      (let ((x (first arguments)))
        (every (lambda (y)
                 (equal x y))
               (rest arguments)))))

      

(equal* 1 1 1 1)
;=> T

      



In fact, since you can call the first one and rest with an empty list, you can even get rid of the first case, since each will return true when an empty list is passed:

(defun equal* (&rest arguments &aux (x (first arguments)))
  (every (lambda (y)
           (equal x y))
         (rest arguments)))

      

After that, since this might be a common pattern, you can define macros to define them for you:

(defmacro def-n-ary-equality (name predicate &rest args)
  (let ((arguments (gensym (string '#:arguments-)))
        (x (gensym (string '#:x-)))
        (y (gensym (string '#:y-))))
    `(defun ,name (&rest ,arguments &aux (,x (first ,arguments)))
       (every (lambda (y)
                (,predicate ,x ,y ,@args))
              (rest ,arguments)))))

      

(def-n-ary-equality equal* equal)
; ==
(DEFUN EQUAL* (&REST #:ARGUMENTS-1005 &AUX (#:X-1006 (FIRST #:ARGUMENTS-1005)))
  (EVERY (LAMBDA (Y)
           (EQUAL #:X-1006 #:Y-1007))
         (REST #:ARGUMENTS-1005)))

      

+3


source


For example, you can compare each item to the first, something like this:



(defun meql (func &rest args)
  (every (lambda (arg)
           (funcall func arg (first args)))
         (rest args)))

CL-USER> (meql #'eq 'a 'a 'a) 
T
CL-USER> (meql #'eq 'a 'b 'a)
NIL
CL-USER> (meql #'equal "foo" "FOO" "foo")
NIL
CL-USER> (meql #'equalp "foo" "FOO" "foo")
T

      

+4


source







All Articles