Vin*_*inn 3 methods function common-lisp clos generic-function
在这个答案中,用户给出了一个非常清晰的示例,说明类和方法如何协同工作。
我将在这里重印该示例:
(defclass human () ())
(defclass dog () ())
(defmethod greet ((thing human))
  (print "Hi human!"))
(defmethod greet ((thing dog))
  (print "Wolf-wolf dog!"))
(defparameter Anna (make-instance 'human))
(defparameter Rex (make-instance 'dog))
(greet Anna) ;; => "Hi human"
(greet Rex)  ;; => "Wolf-wolf dog!"
我的问题是,使用相同的示例:
似乎通用函数是在后台隐式创建的(不是 100% 确定)。我注意到,当我使用这个示例时,如果我创建一个具有与该方法的第一个实例不同的参数结构的方法,我会得到一个generic function error.
创建通用函数会增加什么价值?
我喜欢显式声明泛型函数,因为可以添加与泛型函数相关的文档和声明(针对速度/空间/调试进行优化),以及其他细节,例如方法组合(也称为当您有多种适用于给定的调用,这定义了执行哪些以及按什么顺序执行)。例如,我可以定义talk为具有progn方法组合(所有方法都像封装在progn表单中一样执行):
(defgeneric talk (subject)
  (:documentation "Say something to standard output")
  (:method-combination progn))
这是一个有点做作的例子,但我们开始吧:
(defclass human () ())
(defmethod talk progn ((a human))
  (print "hello"))
(defclass wolf () ())
(defmethod talk progn ((a wolf))
  (print "owooooo!"))
(defclass werewolf (human wolf) ())
talk定义从两者继承的类意味着对该类实例的调用可以执行两个方法(按称为方法解析顺序的某种拓扑顺序排序)。因此,通过这种方法组合,所有方法都会被执行:
* (talk (make-instance 'werewolf))
"hello" 
"owooooo!"
但是,我想说,能够记录通用函数本身就是使用defgeneric.
为什么泛型函数有用?
如果您定义talk为通用函数,则允许任何类参与调用的代码talk(例如库),这是一种允许扩展而不必关闭可能值集的方法,这与typecase在函数中使用类似的东西不同,您可以仅列出一组预定义的案例。
例如,print-object在 Lisp 实现中(在检查器、REPL、调试器中)的不同时间调用标准函数,如果您愿意,您可以为自定义类型实现方法,而不必破坏环境的内部结构。
它们是否像其他面向对象语言中提供结构的实例一样?
与其他 OO 语言不同,泛型函数不依赖于单个类或实例。它们可以针对多个参数进行专门化1 ,这意味着它们都不“拥有”通用函数。
1 . 专业定义如下:
专门化 vt(泛型函数)来定义泛型函数的方法,或者换句话说,通过为特定的一组类或参数赋予特定含义来细化泛型函数的行为。
这背后的想法是方法可以或多或少具体:一种具有两个参数的方法a,并且b专门针对(a number),并且(b string)比另一种仅专门针对 的方法更具体(b vector),并且方法实际上是从最具体到最不具体的方法排序的(分别从最少到最多)组合它们时。您甚至可以专门化一个函数来(a (eql 10))仅涵盖参数为 10 的特定a情况eql。