clojure – 协议继承

有时在接口上有一个继承结构很方便:

例如:

>我想定义一个提供fmap功能的Functor接口.
>我想定义一个Applicative接口,它提供了fapply和pure函数.

但是每个applicative functor都是一个仿函数:( def fmap#(fapply(pure%1)%2)).

我找到的第一个解决方案如下:

>将Functor和Applicative定义为独立协议.
>定义仿函数?函数,对任何Functor或Applicative实例返回true.
>定义fmap mulimethod,它可以使用Functor或Applicative并发送
到#(functor / fmap%1%2)或#(applicative / fapply(applicative / pure%1)%2).

然而,这种解决方案闻起来像是在欺骗一个clojure类型的系统.

第二种解决方案是定义一个宏扩展应用程序,它将自动实现Functor协议.但是这个解决方案看起来并不好看,因为它需要来自库用户的额外工作,并且它允许对functor / applicative实例进行sepparate定义,这很容易导致错误.

在clojure中有没有更好的方式来表达这种关系?

最佳答案 编辑:正如Thumbnail所说,这结果是一个错误的方法 – 我只是测试实现协议接口的记录,并没有注意到扩展Applicative协议实际上没有实现Functor.

请记住,extend不要求被扩展的类型是具体的实现;一个协议可以扩展另一个协议,你也可以扩展接口和抽象类.你应该能够做类似的事情

Applicative.clj

(ns protocol.applicative)
(defprotocol Applicative
      (fapply [f g])
      (pure [x] ))

functor.clj

(ns protocol.functor
  (:import [protocol.applicative.Applicative])
  (:require [protocol.applicative :refer [fapply pure]])
  )

(defprotocol Functor
  (fmap [this f]))

(extend-protocol Functor
  protocol.applicative.Applicative
    (fmap [this f] (fapply (pure f) this)))

多个文件和导入是我尝试处理出现的一些编译顺序问题;你还必须将这两个添加到AOT.希望能帮助您实现目标.

点赞