So I want to compare four different elements, from four different lists. Something like the example bellow, the problem is that equal should only recieve 2 arguments, is there any function to compare more than 2 elements?
(equal (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)))
is there any function to compare more than 2 elements?
Many of the comparison functions in Common Lisp accept more than two arguments. For instance, all of =, /=, <, >, <=, >= accept any number of arguments, which means that 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 need the specific behavior of equal (and not =), then you'll want the approach that coredump proposed. Since equality is transitive, you can check that every element is equal to 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
Actually, since you can call first and rest with the empty list, you could even get rid of the first case, since every will return true when passed the empty list:
(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 could define a macro to define these 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)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With