所以我想比较来自四个不同列表的四个不同元素。就像下面这个例子一样,问题是平等应该只能接收2个参数,是否有任何函数可以比较2个以上的元素?比较多个元素
(equal (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)))
所以我想比较来自四个不同列表的四个不同元素。就像下面这个例子一样,问题是平等应该只能接收2个参数,是否有任何函数可以比较2个以上的元素?比较多个元素
(equal (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)) (nth 0 '(1 2 3)))
没有任何功能比较多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)))
or'(defun equal *(&rest arguments)(every#'equal arguments(rest arguments)))''。 – Svante 2014-12-08 09:53:42
@Svante哦,这很好,并以不同的方式利用了等式谓词的传递性。太好了! – 2014-12-08 17:45:38
例如你可以用第一个,类似的东西,每一个元素比较:
(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
在一般情况下这不是一个错误的选项,而且它是实现n元比较/等式谓词的简单方法。然而,在OP的情况下,它的数字是被比较的,'='操作符可能会工作,并且已经是n-ary了。 – 2014-12-05 16:49:36
如果你只是比较数字,你可以使用接受任意数量参数的'='。 – 2014-12-05 16:46:48