gpt4 book ai didi

clojure - Clojure 中关闭记录背后的基本原理是什么?

转载 作者:行者123 更新时间:2023-12-02 04:43:52 25 4
gpt4 key购买 nike

我可以选择直接在 defrecord 主体中实现协议(protocol),而不是使用扩展协议(protocol)/扩展类型

(defprotocol Fly
(fly [this]))

(defrecord Bird [name]
Fly
(fly [this] (format "%s flies" name)))

=>(fly (Bird. "crow"))
"crow flies"

如果我现在尝试覆盖 Fly 协议(protocol),则会收到错误

(extend-type Bird
Fly
(fly [this] (format "%s flies away (:name this)))

class user.Bird already directly implements interface user.Fly for protocol:#'user/Fly

另一方面,如果我最初使用扩展类型

(defrecord Dragon [color])

(extend-type Dragon
Fly
(fly [this] (format "%s dragon flies" (:color this))))

=>(fly (Dragon. "Red"))
"Red dragon flies"

然后我可以“覆盖”飞行功能

(extend-type Dragon
Fly
(fly [this] (format "%s dragon flies away" (:color this))))

=>(fly (Dragon. "Blue"))
"Blue dragon flies away"

我的问题是,为什么在这两种情况下都不允许延期?这是由于 Record <-> Class 关系而导致的 JVM 限制,还是存在不可重写协议(protocol)的用例?

最佳答案

在某种程度上,这是 JVM 不允许方法实现在类中换入换出的问题,因为实现内联协议(protocol)相当于让由 defrecord 创建的类实现一个接口(interface)对应协议(protocol)。请注意,虽然选择这样做确实牺牲了一些灵 active ,但它也购买了速度——实际上速度是这里的主要设计考虑因素。

在另一个层面上,由不拥有相关类型或协议(protocol)的代码提供类型的协议(protocol)实现通常是一个非常糟糕的主意。例如,参见this thread在 Clojure Google 小组上进行相关讨论(包括 Rich Hickey 的声明); Clojure Library Coding Standards 中也有相关条目:

Protocols:

  • One should only extend a protocol to a type if he owns either the type or the protocol.
  • If one breaks the previous rule, he should be prepared to withdraw, should the implementor of either provide a definition
  • If a protocol comes with Clojure itself, avoid extending it to types you don't own, especially e.g. java.lang.String and other core Java interfaces. Rest assured if a protocol should extend to it, it will, else lobby for it.
    • The motive is, as stated by Rich Hickey, [to prevent] "people extend protocols to types for which they don't make sense, e.g. for which the protocol authors considered but rejected an implementation due to a semantic mismatch.". "No extension will be there (by design), and people without sufficient understanding/skills might fill the void with broken ideas."

Haskell 社区中也对与类型类相关的问题进行了很多讨论(谷歌“孤立实例”;这里也有一些关于该主题的好帖子)。

现在显然,内联实现始终由类型所有者提供,因此不应被客户端代码替换。因此,我可以看到协议(protocol)方法替换仍然有两个有效的用例:

  1. 在 REPL 上进行测试并应用快速调整;

  2. 修改正在运行的 Clojure 镜像中的协议(protocol)方法实现。

(1) 如果在开发时使用 extend & Co. 并且仅在某些后期性能调整阶段切换到内联实现,那么问题可能就不那么大了;如果需要最高速度,(2) 只是人们可能不得不牺牲的东西。

关于clojure - Clojure 中关闭记录背后的基本原理是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3589569/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com