4

免责声明

尽管有标题,但这是一个真正的问题,而不是 Emacs/Vi 火焰大战的尝试。

语境

我已经使用 Haskell 几个月了,并编写了一个小型的 ~10K LOC 解释器。在过去的一年里,我切换到了 Clojure。有一段时间,我为 Clojure 缺乏类型而苦苦挣扎。然后我切换到在 Clojure 中使用 defrecords,现在切换到 Clojure 的 defprotocols。

我真的很喜欢defprotocols。其实不止种类。

我现在正处于我的 Clojure 函数的地步,因为它是文档字符串,我只是指定:

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

使用它,我现在似乎有一个临时类型系统(不是编译器检查;而是人工检查)。

问题

我怀疑我缺少一些关于类型的东西。类型通过协议提供什么?

4

3 回答 3

3

质疑问题...

您的问题“类型通过协议提供什么?” 对我来说似乎很尴尬。类型和协议是垂直的;他们描述不同的事物。类型/记录定义了数据的结构,而协议定义了某些行为或功能的结构。这个问题对我来说很奇怪的部分原因是这些事情并不是相互排斥的!您可以让类型实现协议,从而为它们提供协议描述的任何行为/功能。事实上,由于您的上下文清楚地表明您一直使用协议,我不得不想知道您是如何使用它们的。我的猜测是您一直在将它们与记录一起使用(或可能将它们具体化),但是您可以轻松地将协议和(def)类型一起使用。

所以对我来说,您似乎在这里将苹果与橙子进行了比较。为了帮助澄清,让我将苹果与苹果和橙子与橙子进行比较,并提出几个不同的问题:

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

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

  • 多方法:具有极其灵活的价值。您可以通过type作为分派函数传递类型来分派行为,但您也可以使用任何其他任意函数进行分派。
  • 内部函数逻辑:您也可以(当然)在函数定义中手动检查条件中的类型,以决定如何在给定不同类型的情况下进行不同的处理。这比多方法分派更原始,扩展性也更差。除了在简单的情况下,多方法是首选。

协议具有更高性能的优势,基于高度优化的 JVM 类/方法分派。此外,协议被设计用来解决表达问题(很好读),这使得它们成为制作漂亮、模块化、可扩展的 API 的真正强大工具。

(def)记录或具体化(def)类型的优点/缺点是什么?

在我们如何指定data 的结构方面,我们有许多可用的选项:

  • (def)records:生成一个适合“表示应用程序域信息”的类型(来自http://clojure.org/datatypes;值得一读)
  • (def)types:为创建“实现/编程域的工件”生成更轻量级的类型,例如标准集合类型
  • reify:构造一个一次性对象,其匿名类型实现一个或多个协议;适合...需要实现协议的一次性事物

实际上,记录的行为类似于 clojure 哈希映射,但具有能够实现协议和更快的属性查找的额外好处。方便的是,仍然可以通过 扩展assoc,尽管以这种方式添加的属性不共享编译后的查找性能。这就是使这些构造便于实现应用逻辑的原因。使用 deftype 对于实现/编程领域的各个方面是有利的,因为它们不会实现多余的包,使这些情况下的使用更清洁。

于 2015-01-11T07:34:04.220 回答
0

协议创建接口,接口是一个类型的接口。它们描述了一种类型的某些方面,尽管比您在 Haskell 等语言中所期望的要严格得多。

于 2012-05-22T23:48:47.260 回答
0
  • 机器检查
  • 类型推断(您的某些协议不会从其他人的文档中生成)
  • 参数多态性(参数化协议/具有泛型的协议不存在)
  • 高阶协议(返回协议的函数的协议是什么?)
  • 自动生成代码/样板
  • 与自动化工具的互操作
于 2012-05-23T01:24:58.123 回答