不能在通用函数方法中使用变量吗? (CLOS / LISP)

时间:2017-01-04 23:19:56

标签: lisp common-lisp clos generic-function

我正在学习CLOS中的通用功能。

由于我在教科书和网上找到的例子类型,我感到非常困惑。这些示例总是使用多个调度的事实。根据参数类型,执行不同的计算。但是,为什么参数本身从未在示例中使用过?

  

来自Wikipedia

的示例代码
; declare the common argument structure prototype
(defgeneric f (x y)) 

; define an implementation for (f integer t), where t matches all types
(defmethod f ((x integer) y) 1) 

(f 1 2.0) => 1

; define an implementation for (f integer real)
(defmethod f ((x integer) (y real)) 2) 

(f 1 2.0) => 2 ; dispatch changed at runtime

在上面的示例中,您可以看到方法本身从未实际使用xy变量。所有这些例子都不使用变量,这是巧合吗?可以使用它们吗?

另外,它写在Wikipedia上:

  

方法是与类别分开定义的,并且它们没有特殊的访问权限(例如"这个"," self"或者#34; protected")到类槽。

好吧,所以方法没有"这个"因为他们不属于一个班级。但是为什么泛型函数方法有接收器呢?不是接收器类似于'这个'在课堂上?

2 个答案:

答案 0 :(得分:5)

当然,您可以从参数列表中访问变量。维基百科示例仅用于说明哪个方法返回值。

  

但为什么泛型函数方法有接收器呢?不是接收器类似于'这个'在课堂上?

CLOS通用功能没有单个接收器,因此使用接收器这个词是没有意义的。您提到的实现可能没有实现完整的CLOS,而是没有多个调度的变体。

CLOS示例:

CL-USER 8 > (defmethod plus ((s1 string) (s2 string))
              (concatenate 'string s1 s2))
#<STANDARD-METHOD PLUS NIL (STRING STRING) 4020001E6B>

CL-USER 9 > (plus "foo" "bar")
"foobar"

您会看到使用了两个变量s1s2。为其中一个receiver命名是没有意义的。

但是您可以根据需要命名变量,当您的应用程序仅使用第一个参数的调度时,您可能希望调用该变量receiver,但该名称对CLOS没有语义。这只是另一个名字。

一般来说,对于CLOS代码,最好给参数提供有用的名称。

这是误导性的,因为我们没有在CLOS中进行消息传递

(defmethod plus ((receiver string) (argument string))
   (concatenate 'string receiver argument))

这更有用:

(defmethod plus ((string-1 string) (string-2 string))
   (concatenate 'string string-1 string-2))

答案 1 :(得分:3)

这些示例仅显示了基于类型的调度工作方式,因此他们不必费心使用这些变量。但你当然可以,例如。

(defmethod f ((x integer) (y symbol))
    (* x x))

(f 3 'foo) => 9

使用接收器只是一种惯例。如果要像其他OOP语言一样使用CLOS,则可能只调度第一个参数的类型。您可以将其命名为thisself以使意图明确。