Clojure协议 vs 类型

4

免责声明

尽管标题如此,这是一个真正的问题,而不是Emacs/Vi的争论。

背景

我使用Haskell几个月,并编写了一个小型的约10K行代码的解释器。在过去的一年中,我转向了Clojure。相当长一段时间里,我为Clojure缺乏类型而苦恼。然后我开始使用Clojure中的defrecords,现在则改用Clojure的defprotocols。

我非常喜欢defprotocols。事实上,比类型更喜欢。

现在我的Clojure函数的文档字符串已经到了这样的程度:

* the protocols of the inputs
* the protocols of the outputs

使用这种方法,看起来我现在拥有了一种临时的类型系统(未经编译器检查;但是经过人工检查)。
问题
我怀疑自己对类型方面有所遗漏。类型相对于协议提供了什么?
3个回答

3

质疑问题的问题...

您的问题"What [do] types provide over protocols?"让我感到很奇怪。类型和协议是垂直的,它们描述不同的东西。类型/记录定义数据结构,而协议定义行为或功能的结构。这个问题对我来说之所以看起来奇怪,部分原因在于这些东西不是相互排斥的!您可以让类型实现协议,从而赋予它们协议描述的任何行为/功能。事实上,由于您的上下文清楚地表明您一直在使用协议,我不禁想是如何使用它们的。我的猜测是,您将它们与记录(或可能是重构)一起使用,但是您也可以轻松地同时使用协议和(def)types。

所以在我的理解中,您在这里将苹果与橙子进行了比较。为了帮助澄清,让我用一些不同的问题比较苹果和苹果,橙子和橙子:

协议解决了什么问题?有哪些替代方案及其各自的优缺点?

协议允许您定义在不同类型上以不同方式运行的函数。唯一的其他方法是多重方法和简单函数逻辑:

  • 多重方法:具有极其灵活性的价值。您可以通过将type作为调度函数来按类型分派行为,但您也可以使用任何其他任意函数进行调度。
  • 内部函数逻辑:当然,您还可以在函数定义中手动检查类型以决定如何处理不同的类型。这比多重方法调度更原始,而且也不太可扩展。除非在简单情况下,否则多重方法被认为是更好的选择。

协议的优点在于它们基于JVM类/方法调度,性能更高,经过高度优化。此外,协议旨在解决表达式问题(非常精彩),使它们成为构建漂亮、模块化、可扩展的API的强大工具。

(def)记录或重构与(def)类型相比的优缺点是什么?

在我们指定数据结构的方式方面,我们有许多选项可用:

  • (def)记录:产生适用于“表示应用程序领域信息”的类型(从http://clojure.org/datatypes中得出;值得一读)
  • (def)types:生成轻量级类型,用于创建“实现/编程域的工件”,如标准集合类型
  • 重构:构造一个匿名类型的一次性对象,该对象实现了一个或多个协议;适用于需要实现协议的一次性事物

实际上,记录表现得像Clojure哈希映射,但具有能够实现协议和更快的属性查找的额外优点。方便地,它们通过assoc保持可扩展性,尽管以这种方式添加的属性不共享编译后的查找性能。这使得这些结构在实现应用逻辑时非常方便。在实现/编程领域使用deftype是有优势的,因为它们不会实现多余的东西,使得在这些情况下使用更加简洁。


0

协议创建接口,而接口是一个井,是类型的接口。它们描述了类型的某些方面,但比您在像Haskell这样的语言中期望的严谨程度要低得多。


0
  • 机器检查
  • 类型推断(您无法从其他人的文档中生成一些协议)
  • 参数多态性(不存在带有泛型的参数化协议/协议)
  • 高阶协议(返回协议的函数的协议是什么?)
  • 自动生成代码/样板文件
  • 与自动化工具的互操作性

协议已经是多态的。协议支持委托,因此您可以实现一个返回实现协议的内容的协议,从而使协议的组合变得非常容易。您提出的其他一些观点是正确的,但在Lisp的上下文中有些不相关。 - dnolen
你能解释一下多态吗?我加了“参数化”的概念,因为在这个上下文中,明确表达意思是很清楚的吧?此外,“与Lisp无关”的说法似乎有点奇怪,因为整个想法是让它更不像Lisp/与其他语言进行比较。不过我会看一下委托的,谢谢。 - andrew cooke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接