所以我想比较来自四个不同列表的四个不同元素。类似于下面的例子,问题是相等应该只接收2个参数,是否有任何函数可以比较2个以上的元素?
(equal (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)))
答案 0 :(得分:4)
例如,您可以将每个元素与第一个元素进行比较,类似于:
(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
答案 1 :(得分:4)
是否有任何比较2个以上元素的函数?
Common Lisp中的许多比较函数都接受两个以上的参数。例如,所有=, /=, <, >, <=, >=都接受任意数量的参数,这意味着您可以执行
(= (nth 0 '(1 2 3))
(nth 0 '(1 2 3))
(nth 0 '(1 2 3))
(nth 0 '(1 2 3)))
如果您需要相等(而不是 = )的特定行为,那么您将需要coredump proposed的方法。由于相等性是可传递的,因此您可以检查每个元素是否与第一个元素相等(或者列表为空):
(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
实际上,由于您可以使用空列表调用第一个和休息,您甚至可以摆脱第一个案例,因为每个传递空列表时将返回true:
(defun equal* (&rest arguments &aux (x (first arguments)))
(every (lambda (y)
(equal x y))
(rest arguments)))
之后,由于这可能是一种常见的模式,您可以定义一个宏来为您定义这些模式:
(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)))