Clojure 多方法如何解决名称空间问题?
我正在研究编程语言设计,我感兴趣的问题是如何用多方法泛型函数范式取代流行的单一分派消息传递OO范式。在大多数情况下,这似乎很简单,但我最近陷入困境,希望能得到一些帮助 在我看来,消息传递OO是解决两个不同问题的一种解决方案。我将在下面的伪代码中详细解释我的意思 (1) 它解决了调度问题: ==在文件animal.code中===Clojure 多方法如何解决名称空间问题?,clojure,lisp,common-lisp,language-design,multimethod,Clojure,Lisp,Common Lisp,Language Design,Multimethod,我正在研究编程语言设计,我感兴趣的问题是如何用多方法泛型函数范式取代流行的单一分派消息传递OO范式。在大多数情况下,这似乎很简单,但我最近陷入困境,希望能得到一些帮助 在我看来,消息传递OO是解决两个不同问题的一种解决方案。我将在下面的伪代码中详细解释我的意思 (1) 它解决了调度问题: ==在文件animal.code中=== - Animals can "bark" - Dogs "bark" by printing "woof" to the screen. - Cats
- Animals can "bark"
- Dogs "bark" by printing "woof" to the screen.
- Cats "bark" by printing "meow" to the screen.
- Animals can "bark"
- define generic function bark(Animal a)
- define method bark(Dog d) : print("woof")
- define method bark(Cat c) : print("meow")
- define generic function bark(Animal a)
define module animals
define class animal
// methods doesn't use "bark(animal AANIMAL)"
define method bark()
...
end define method
end define class
define class dog
// methods doesn't use "bark(dog ADOG)"
define method bark()
...
end define method
end define class
end define module
==在文件myprogram.code中===
import animal.code
for each animal a in list-of-animals :
a.bark()
import animal.code
import tree.code
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
import animal.code
for each animal a in list-of-animals :
bark(a)
import animal.code
import tree.code
a = new-dog()
bark(a) /// Which bark function are we calling?
t = new-tree
bark(t) /// Which bark function are we calling?
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
obj.get-x()
pt = new-point()
pt.get-x()
gene = new-point()
gene.get-x()
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
XYZ:get-x(obj)
pt = new-point()
POINT:get-x(pt)
gene = new-point()
GENE:get-x(gene)
define module myprogram
import animals.code
import trees.code
define function main
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
end define function main
end define module
在这个问题中,“bark”是一个具有多个“分支”的方法,这些分支根据参数类型进行不同的操作。对于我们感兴趣的每种参数类型(狗和猫),我们实现“吠叫”一次。在运行时,我们能够遍历动物列表并动态选择要执行的相应分支
(2) 它解决了名称空间问题:
==在文件animal.code中===
- Animals can "bark"
- Dogs "bark" by printing "woof" to the screen.
- Cats "bark" by printing "meow" to the screen.
- Animals can "bark"
- define generic function bark(Animal a)
- define method bark(Dog d) : print("woof")
- define method bark(Cat c) : print("meow")
- define generic function bark(Animal a)
define module animals
define class animal
// methods doesn't use "bark(animal AANIMAL)"
define method bark()
...
end define method
end define class
define class dog
// methods doesn't use "bark(dog ADOG)"
define method bark()
...
end define method
end define class
end define module
==在文件树中。代码===
- Trees have "bark"
- define generic function bark(Tree t)
==在文件myprogram.code中===
import animal.code
for each animal a in list-of-animals :
a.bark()
import animal.code
import tree.code
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
import animal.code
for each animal a in list-of-animals :
bark(a)
import animal.code
import tree.code
a = new-dog()
bark(a) /// Which bark function are we calling?
t = new-tree
bark(t) /// Which bark function are we calling?
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
obj.get-x()
pt = new-point()
pt.get-x()
gene = new-point()
gene.get-x()
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
XYZ:get-x(obj)
pt = new-point()
POINT:get-x(pt)
gene = new-point()
GENE:get-x(gene)
define module myprogram
import animals.code
import trees.code
define function main
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
end define function main
end define module
在这个问题中,“树皮”实际上是两个概念上不同的函数,它们恰好具有相同的名称。参数的类型(是狗还是树)决定了我们实际指的是哪个函数
多种方法优雅地解决了问题1。但我不明白他们是如何解决第二个问题的。例如,上述两个示例中的第一个可以直接转换为多方法: (1) 使用多种方法的狗和猫 ==在文件animal.code中===
- Animals can "bark"
- Dogs "bark" by printing "woof" to the screen.
- Cats "bark" by printing "meow" to the screen.
- Animals can "bark"
- define generic function bark(Animal a)
- define method bark(Dog d) : print("woof")
- define method bark(Cat c) : print("meow")
- define generic function bark(Animal a)
define module animals
define class animal
// methods doesn't use "bark(animal AANIMAL)"
define method bark()
...
end define method
end define class
define class dog
// methods doesn't use "bark(dog ADOG)"
define method bark()
...
end define method
end define class
end define module
==在文件myprogram.code中===
import animal.code
for each animal a in list-of-animals :
a.bark()
import animal.code
import tree.code
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
import animal.code
for each animal a in list-of-animals :
bark(a)
import animal.code
import tree.code
a = new-dog()
bark(a) /// Which bark function are we calling?
t = new-tree
bark(t) /// Which bark function are we calling?
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
obj.get-x()
pt = new-point()
pt.get-x()
gene = new-point()
gene.get-x()
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
XYZ:get-x(obj)
pt = new-point()
POINT:get-x(pt)
gene = new-point()
GENE:get-x(gene)
define module myprogram
import animals.code
import trees.code
define function main
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
end define function main
end define module
关键的一点是,吠声(狗)的方法在概念上与吠声(猫)相关。第二个示例没有这个属性,这就是为什么我不理解多方法如何解决名称空间问题
(2) 为什么多种方法不适用于动物和树木
==在文件animal.code中===
- Animals can "bark"
- Dogs "bark" by printing "woof" to the screen.
- Cats "bark" by printing "meow" to the screen.
- Animals can "bark"
- define generic function bark(Animal a)
- define method bark(Dog d) : print("woof")
- define method bark(Cat c) : print("meow")
- define generic function bark(Animal a)
define module animals
define class animal
// methods doesn't use "bark(animal AANIMAL)"
define method bark()
...
end define method
end define class
define class dog
// methods doesn't use "bark(dog ADOG)"
define method bark()
...
end define method
end define class
end define module
==在文件树中。代码===
- Trees have "bark"
- define generic function bark(Tree t)
==在文件myprogram.code中===
import animal.code
for each animal a in list-of-animals :
a.bark()
import animal.code
import tree.code
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
import animal.code
for each animal a in list-of-animals :
bark(a)
import animal.code
import tree.code
a = new-dog()
bark(a) /// Which bark function are we calling?
t = new-tree
bark(t) /// Which bark function are we calling?
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
obj.get-x()
pt = new-point()
pt.get-x()
gene = new-point()
gene.get-x()
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
XYZ:get-x(obj)
pt = new-point()
POINT:get-x(pt)
gene = new-point()
GENE:get-x(gene)
define module myprogram
import animals.code
import trees.code
define function main
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
end define function main
end define module
在这种情况下,应该在哪里定义泛型函数?它应该在动物和树木之上的顶层定义吗?将动物树皮和树木树皮视为具有相同通用功能的两种方法是没有意义的,因为这两种功能在概念上是不同的
据我所知,我还没有发现任何过去的工作能够解决这个问题。我研究了Clojure多方法和CLOS多方法,它们都有相同的问题。我交叉着手指,希望找到一个优雅的解决方案,或者是一个有说服力的论据,说明为什么它在实际编程中不是问题
如果问题需要澄清,请告诉我。我认为这是一个相当微妙(但很重要)的观点
谢谢你的回复,理智,雷纳,马辛和马提亚。我理解您的答复,并且完全同意动态分派和名称空间解析是两件不同的事情。CLOS并没有将这两种思想混为一谈,而传统的消息传递OO却做到了这一点。这还允许将多方法直接扩展到多继承 我的问题特别是在需要合并的情况下 下面是我的意思的一个例子 ==文件:XYZ.code===
define class XYZ :
define get-x ()
define get-y ()
define get-z ()
define generic function get-x (XYZ)
define generic function get-y (XYZ)
define generic function get-z (XYZ)
==文件:POINT.code===
define class POINT :
define get-x ()
define get-y ()
define generic function get-x (POINT)
define generic function get-y (POINT)
==文件:GENE.code===
define class GENE :
define get-x ()
define get-xx ()
define get-y ()
define get-xy ()
define generic function get-x (GENE)
define generic function get-xx (GENE)
define generic function get-y (GENE)
define generic function get-xy (GENE)
==文件:我的程序代码===
import animal.code
for each animal a in list-of-animals :
a.bark()
import animal.code
import tree.code
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
import animal.code
for each animal a in list-of-animals :
bark(a)
import animal.code
import tree.code
a = new-dog()
bark(a) /// Which bark function are we calling?
t = new-tree
bark(t) /// Which bark function are we calling?
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
obj.get-x()
pt = new-point()
pt.get-x()
gene = new-point()
gene.get-x()
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
XYZ:get-x(obj)
pt = new-point()
POINT:get-x(pt)
gene = new-point()
GENE:get-x(gene)
define module myprogram
import animals.code
import trees.code
define function main
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
end define function main
end define module
由于名称空间解析与分派的结合,程序员可以天真地对所有三个对象调用get-x()。这也是非常明确的。每个对象“拥有”自己的一组方法,因此对于程序员的意思没有任何混淆
与多方法版本相比:
==文件:XYZ.code===
define class XYZ :
define get-x ()
define get-y ()
define get-z ()
define generic function get-x (XYZ)
define generic function get-y (XYZ)
define generic function get-z (XYZ)
==文件:POINT.code===
define class POINT :
define get-x ()
define get-y ()
define generic function get-x (POINT)
define generic function get-y (POINT)
==文件:GENE.code===
define class GENE :
define get-x ()
define get-xx ()
define get-y ()
define get-xy ()
define generic function get-x (GENE)
define generic function get-xx (GENE)
define generic function get-y (GENE)
define generic function get-xy (GENE)
==文件:我的程序代码===
import animal.code
for each animal a in list-of-animals :
a.bark()
import animal.code
import tree.code
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
import animal.code
for each animal a in list-of-animals :
bark(a)
import animal.code
import tree.code
a = new-dog()
bark(a) /// Which bark function are we calling?
t = new-tree
bark(t) /// Which bark function are we calling?
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
obj.get-x()
pt = new-point()
pt.get-x()
gene = new-point()
gene.get-x()
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
XYZ:get-x(obj)
pt = new-point()
POINT:get-x(pt)
gene = new-point()
GENE:get-x(gene)
define module myprogram
import animals.code
import trees.code
define function main
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
end define function main
end define module
因为XYZ的get-x()与GENE的get-x()没有概念关系,所以它们被实现为单独的泛型函数。因此,终端程序员(在my_program.code中)必须显式地限定get-x(),并告诉系统他实际上要调用哪个get-x()
诚然,这种显式方法更清晰,也更容易推广到多重分派和多重继承。但是使用(滥用)分派来解决名称空间问题是消息传递OO的一个非常方便的特性
我个人认为,我自己的代码有98%是使用单一分派和单一继承来充分表达的。我使用dispatch进行名称空间解析的这种便利性要比使用多个dispatch方便得多,所以我不愿意放弃它
有没有办法让我两全其美?如何避免在多方法设置中显式限定函数调用
看来大家的共识是
- 多方法可以解决分派问题,但不会攻击命名空间问题
- 概念上不同的函数应该有不同的名称,用户应该手动对它们进行限定