【问题标题】:What is reify in Clojure?Clojure 中的具体化是什么?
【发布时间】:2016-08-31 16:39:35
【问题描述】:

我无法理解 Clojure 中 reify 函数的用法。 它在clojure中是做什么用的?

你能提供例子吗?

【问题讨论】:

标签: clojure


【解决方案1】:

reifydefrecord fndefn
“啊对……那reify是什么”

简单地说,协议是数据类型应该支持的功能列表,记录是数据类型,具体化是匿名数据类型。

也许这有点啰嗦,但是如果不了解协议和类型/记录,就无法具体理解 reify:协议是一种对诸如 conj 之类的函数使用相同名称的方法,它实际上在以下情况下的行为会有所不同给定不同的论点((conj [:b :c] :a) => [:b :c :a](conj '(:b :c) :a) => (:a :b :c))。记录就像对象或类型(但它们的行为就像地图,让它们更棒)。

更根本的是,目标是解决“表达式问题”,即能够无缝添加与现有函数配合使用的新类型数据,以及与现有数据无缝配合的新函数.

所以有一天你对自己说:“你自己,你应该了解做一只鸭子意味着什么!”所以你写了一个协议:

(defprotocol Quacks
  (quack [_] "should say something in ducky fashion"))

但它太抽象了,所以你'真实化'它:

(def donald (reify Quacks
                   (quack [_] "Quacks and says I'm Donald")))

现在你终于可以体验你的创作了:

(quack donald) => "Quacks and says I'm Donald"

那你还记得达菲:

(def daffy (reify Quacks
                  (quack [_] (str "Quacks and says I'm Daffy"))))

(quack daffy) => "Quacks and says I'm Daffy"

但是当您想起 Huey 时,您就会意识到自己的错误并以可重复使用的方式定义鸭子是什么:

(defrecord Duck [name]
  Quacks
  (quack [_] (str "Quacks and says I'm " name)))

并制作new鸭子(有几种方法可以做到):

(def huey (->Duck "Huey"))
(def duey (Duck. "Duey"))
(def louie (new Duck "Louie"))

(quack huey) => "Quacks and says I'm Huey"

请记住,记录就像地图一样(感谢协议!):

(:name huey) => "Huey"

但是你记得鸭子必须呱呱叫走路,所以你写了另一个协议:

(defprotocol Walks
  (walk [_] "should walk like a duck"))

并扩展duck的定义

(extend-type Duck
  Walks
  (walk [_] "waddle waddle"))

(walk louie) => "waddle waddle"

现在我们可以扩展其他类型来实现相同的协议(教相同的函数如何使用其他东西):

所以假设我们希望程序员也能嘎嘎:-)

(defrecord Programmer [] Quacks
  (quack [_] "Monads are simply monoids in a category of endofunctors..."))

(quack (Programmer.)) => "Monads are simply monoids in a category of endofunctors..."

我推荐这个很棒的 explanation of protocolsexplanation of reifychapter on protocols in "Clojure for the Brave and True"

免责声明:这只是为了初步了解协议是什么,不是关于如何使用它们的最佳实践。 “Psst!我回答这个问题主要是为了自学,因为直到昨天我还没有真正编写过自己的协议/接口!”

因此,虽然我希望它可以提高其他人的学习能力,但我衷心欢迎批评或编辑建议!”。

【讨论】:

  • 我喜欢你的回答!实际的解释和幽默。正如费曼曾经说过的,尝试向他人解释某事是了解自己的最佳方式。
【解决方案2】:

reify 宏允许创建一个匿名类扩展java.lang.Object 类和/或实现指定的接口/协议。 API docs 没有清楚地描述目的,而是提供了该宏的功能的技术细节。 Java interop documentation 提供了目的的简要说明:

从 Clojure 1.2 开始,reify 也可用于实现 接口。

更多信息可以在datatypes documentation 中找到,您可以在其中找到非常详细的描述它的作用以及它与proxy 的比较:

虽然 deftype 和 defrecord 定义了命名类型,但 reify 定义了一个 匿名类型并创建该类型的实例。用例是 您需要一次性实现一个或多个协议或 接口,并希望利用本地上下文。在 这方面它是类似于代理或匿名内部的用例 Java 中的类。

reify 的方法体是词法闭包,可以参考 围绕局部范围。 reify 与代理的不同之处在于:

仅支持协议或接口,不支持具体的超类。 方法体是结果类的真正方法,而不是 外部fns。在实例上调用方法是直接的,而不是 使用地图查找。不支持动态交换方法 方法图。结果是比代理更好的性能,无论是在 构造和调用。在所有情况下,reify 都优于代理 它的约束条件并不令人望而却步。

【讨论】:

  • 你不能用reify扩展一个类(Object除外),所以你的第一句话有点不正确。
  • @NathanDavis 是的,你是对的,我已经确定了我的答案。
猜你喜欢
  • 2016-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-11
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多