2009-10-10 34 views
24

Clojure是一个功能性lisp,尽管它运行在JVM上,但它并不是面向对象的,尽管它运行在面向对象语言的虚拟机JVM上。 Clojure提供了相同的接口,通过将它们抽象为一个名为seq的接口来遍历列表和向量。这甚至在内部使用名为ISeq的Java接口来实现。这不是面向对象抽象的例子吗?如何声称Clojure不是面向对象的?Clojure是否面向对象? (在seqs中的多态性)

我想这个问题的必然结果---何时可以将多态性视为与面向对象不同?

+0

链接到源“据说不是在所有面向对象”将是搞清楚是否论据有帮助技术与政治...... – 2009-10-10 20:34:35

+2

http://clojure.org/rationale谈论面向对象和为什么Clojure避免它。 – 2009-10-11 22:33:46

+0

http://blog.thinkrelevance.com/2009/8/12/rifle-oriented-programming-with-clojure-2是一篇有趣的文章,讨论了Clojure如何实际允许使用所有主要的OO主体。但是我发现很难将它们结合起来。例如使用闭包封装通过继承排除扩展。一般的做法似乎是放弃封装以支持可扩展性。 – 2009-10-12 23:56:30

回答

27

习惯上的Clojure倾向于定义独立的函数,这些函数在一小部分核心数据结构上运行;这种方法和数据的分解是一种强烈的反对客体导向和赞成功能风格的陈述。 Rich Hickey(Clojure的创始人)已多次声明这一点的重要性;例如:"Clojure eschews the traditional object-oriented approach of creating a new data type for each new situation, instead preferring to build a large library of functions on a small set of types."

在Clojure中,对核心数据结构的依赖比在其他函数式语言中更重要,因为当您使用Clojure的持久数据结构时,您只会从Clojure的STM中获得全部好处。

我想这个问题的必然结果---何时可以将多态性视为与面向对象不同?

我使用Clojure的multimethods(即多态设施)根据文件名的扩展名分派到不同的实现 - 不是面向对象,而是多态。

+14

“最好在一个数据结构上运行100个函数,而不是在10个数据结构上运行10个函数。” - Alan J. Perlis – Jonas 2009-10-10 18:24:31

16

我想这个问题的必然结果---何时可以认为多态性与面向对象不同?

多态性与面向对象完全没有关系。它只是意味着,根据操作数的类型,相同的操作可以有不同的表现。

像ML或Haskell这样的函数语言已经有了30多年的多态性,对PL历史有更深入了解的人可能会指出1962年以前的一些例子(即OO之前)。 Christopher Strachey在1967年描述了参数多态性和ad-hoc多态性之间的区别,所以多态性必须有已经存在于之后。由于多态性仅在Simula-67中的OO中引入,因此我猜测多态性在OO中引入之前必须存在

4

Clojures多态性是Java的自然延伸。在java中,方法是按类分派。在clojure中,这个扩展允许你根据你想要的任何东西发送呼叫。它在课堂上派发仍然非常容易,事实上大部分时间都是如此。如果你想要别的东西,那么你可以写你自己的调度员。内置函数derive根据您想要的任何内容创建层次结构,然后在isa上发送。

更多善良的一面:http://clojure.org/multimethods

5

记住的东西像ISEQ是Java。

在Clojure中,seq抽象实际上只是'某些',你可以提供给第一个,休息和第n个函数(注意你不要先调用seq,你先用seq参数调用)。 Clojure语言的核心功能都是对集合,seqs或原始类型进行操作。在暴露的接口中没有与方法捆绑的数据。所以Clojure的实现是用Java编写的,所有与JVM互操作都将涉及类/对象,但是Clojure本身并不支持。

Clojure不鼓励使用数据结构绑定方法。

说了这么多......事实上,功能确实会限制他们将使用哪些参数。第一次休息和第n次只会对可能是seq的东西起作用。从这个角度来看,数据结构是否与方法捆绑在一起没有太大的区别 - 你仍然必须正确匹配它们。大的胜利来自灵活性。函数可以被写入带任何参数,然后用高阶函数组成没有定义类等:

(def farms [{:name "Swansea", :value 100} 
      {:name "Broadmarsh", :value 200, :produce [:corn :wheat :rye]} 
      {:name "Snug", :value 50, :animals [:goats :pigs]}]) 
(reduce + (map :value farms)) 
-> 350 
(reduce + (map :value (filter :animals farms))) 
-> 50