首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >clojure协议的简单说明

clojure协议的简单说明
EN

Stack Overflow用户
提问于 2010-12-22 21:48:13
回答 1查看 18.8K关注 0票数 141

我正在尝试理解clojure协议以及它们应该解决的问题。有没有人清楚地解释了clojure协议的内容和原因?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-12-23 04:46:25

Clojure中协议的目的是以一种有效的方式解决表达式问题。

那么,表达式问题是什么呢?它涉及到可扩展性的基本问题:我们的程序使用操作来操作数据类型。随着程序的发展,我们需要用新的数据类型和新的操作来扩展它们。特别是,我们希望能够添加与现有数据类型一起工作的新操作,并且我们希望能够添加与现有操作一起工作的新数据类型。我们希望这是真正的扩展,即我们不想修改现有的程序,我们希望尊重现有的抽象,我们希望我们的扩展是单独的模块,在单独的命名空间中,单独编译,单独部署,单独类型检查。我们希望它们是类型安全的。注意:并不是所有这些在所有语言中都有意义。但是,例如,即使在Clojure这样的语言中,让它们保持类型安全的目标也是有意义的。仅仅因为我们不能静态地检查类型安全并不意味着我们希望我们的代码随机崩溃,对吧?

表达式问题是,如何在语言中实际提供这样的可扩展性?

事实证明,对于典型的过程和/或函数式编程的朴素实现,添加新的操作(过程、函数)非常容易,但添加新的数据类型却非常困难,因为基本上这些操作使用某种大小写判别(switchcase、模式匹配)来处理数据类型,并且您需要向它们添加新的用例,即修改现有代码:

代码语言:javascript
复制
func print(node):
  case node of:
    AddOperator => print(node.left) + '+' + print(node.right)
    NotOperator => '!' + print(node)

func eval(node):
  case node of:
    AddOperator => eval(node.left) + eval(node.right)
    NotOperator => !eval(node)

对于典型的朴素的OO,你有完全相反的问题:很容易添加新的数据类型来处理现有的操作(通过继承或覆盖它们),但很难添加新的操作,因为这基本上意味着修改现有的类/对象。

代码语言:javascript
复制
class AddOperator(left: Node, right: Node) < Node:
  meth print:
    left.print + '+' + right.print

  meth eval
    left.eval + right.eval

class NotOperator(expr: Node) < Node:
  meth print:
    '!' + expr.print

  meth eval
    !expr.eval

在这里,添加新节点类型很容易,因为您可以继承、覆盖或实现所有必需的操作,但添加新操作很难,因为您需要将其添加到所有叶类或基类中,从而修改现有代码。

注意,Clojure实际上已经有了一种解决表达式问题的机制: Multimethods。面向对象的EP存在的问题是它们将操作和类型捆绑在一起。使用Multimethods,它们是分开的。FP存在的问题是他们将操作和案例判别捆绑在一起。同样,对于多方法,它们是分开的。

因此,让我们将协议与多方法进行比较,因为它们做的是相同的事情。或者,换一种说法:既然我们已经有了多方法,为什么要用协议呢?

与多方法相比,协议提供的主要功能是分组:您可以将多个功能组合在一起,并说“这三个功能一起形成了协议Foo”。你不能用多方法做到这一点,它们总是独立存在的。例如,您可以声明Stack协议同时由pushpop函数组成。

那么,为什么不添加将多方法分组在一起的功能呢?有一个纯粹的实用原因,这就是为什么我在我的介绍性句子中使用了“高效”这个词:性能。

Clojure是一种托管语言。也就是说,它被专门设计为在另一种语言的平台上运行。Clojure Multimethods OTOH调度所有参数的任意属性。

因此,协议限制您只能对第一个参数进行调度,并且只能对其类型进行调度(或者作为nil上的特例)。

这不是对协议本身的想法的限制,它是访问底层平台的性能优化的实用选择。特别是,这意味着协议有一个到JVM/CLI接口的简单映射,这使得它们非常快。实际上,速度足够快,能够在Clojure本身中重写当前用Java或C#编写的Clojure部分。

从1.0版本开始,Clojure实际上就已经有了协议:例如,Seq就是一个协议。但是在1.2版本之前,您不能用Clojure编写协议,您必须用宿主语言编写它们。

票数 302
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4509782

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档