【问题标题】:Lisp custom comparison functionsLisp 自定义比较函数
【发布时间】:2013-11-22 20:53:45
【问题描述】:

假设我定义了一个新类foo

(defclass foo ()
  ((bar :initarg :bar ...)
   (baz :initarg :baz ...)
   ...))

我想为foo创建一个自定义比较器,例如:

(defun foo-equalp (foo1 foo2)
  (equalp (bar foo1)))

是否有更好、更明确的方法将此foo-equalp 函数与foo 类联系起来?

我在考虑不必将 #'foo-equalp 作为 :test 参数传递给像 REMOVE-DUPLICATES 这样的函数,但即使这不可能,我仍然想知道是否有更惯用的 Lisp 方式定义这个函数。

【问题讨论】:

  • 听起来你想要一个等式谓词,它是一个通用函数,可以添加专门的方法(有点像你如何在 Java 中专门化 .equals())。不幸的是,“通用”谓词(eqeqlequalequalp)都不是泛型函数,因此虽然编写这样的泛型函数并不难,但您仍然需要通过它与 remove 等库函数进行比较,因为它不是这些库函数的默认比较。
  • @JoshuaTaylor:你知道cdr.eurolisp.org/document/8/cleqcmp.html 吗?我已经整理了一个 CDR8 的实现,但还没有发布(需要清理并提交)。
  • @PaulNathan 我知道 CDR 存储库,但我之前没有阅读过那个特定的存储库。这看起来是个好主意。我当然会赞成使用它的答案。 :) 我知道你说你还没有发布它,但是它在任何州的任何地方都可以在线获得吗?
  • @JoshuaTaylor: github.com/pnathan/generic-comparability(我也参与过 CDR 2 的实现,但不太成熟)。

标签: common-lisp


【解决方案1】:

如果我理解您的问题,那么 generic functions 可以在这里提供帮助

(defgeneric foo-equalp (foo1 foo2))

(defmethod foo-equalp ((foo1 foo) (foo2 foo))
  (and (equal (bar foo1) (bar foo2))
       (equal (baz foo1) (baz foo2))))

现在,当您使用非 foo 类型的对象调用 foo-equalp 时,您会收到此错误。

There is no applicable method for the generic function
  #<STANDARD-GENERIC-FUNCTION FOO-EQUALP (1)>
when called with arguments
  (1 2).

或者您可能希望其他所有内容都返回 nil

(defmethod foo-equalp ((foo1 t) (foo2 t))
  nil)

在这里,我们专注于t which is the set of all objects。当你调用一个方法时,common lisp 总是会为参数选择“最接近/最具体”的类型匹配(呃,这是一个可怕的描述混乱..我需要更多的咖啡,查看链接,因为它很棒 :))

  • 您实际上不需要专门化 t,因为这是默认设置,但我想包含它以显示发生了什么。

以下是来自 Practical Common Lisp 的 sn-ps(链接在此顶部 回答)

一个泛型函数定义一个抽象操作,指定它的名字 和一个参数列表,但没有实现。实际执行 泛型函数由方法提供。

方法表明它们可以处理哪些类型的参数 专门化泛型函数定义的所需参数。

例如,对于通用函数 draw,您可以定义一种方法 专门化作为实例的对象的形状参数 类 circle 而另一种方法专门用于对象的形状 它们是类三角形的实例。

【讨论】:

  • 当您计划使用继承和/或方法组合使用多种方法对其进行扩展时,请使用泛型函数。否则它可能是矫枉过正。
  • 干杯,我一直对何时选择哪种技术有点模糊。很高兴将此作为经验法则。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多