有时在接口上有一个继承结构很方便: 例如:
Functor
功能的fmap
接口。Applicative
和fapply
功能的pure
界面。但每个applicative functor都是一个仿函数:(def fmap #(fapply (pure %1) %2))
。
我遇到的第一个解决方案如下:
Functor
和Applicative
定义为独立协议。functor?
函数,该函数会为true
或Functor
个实例返回Applicative
。fmap
mulimethod,可以Functor
或Applicative
并发送
到#(functor/fmap %1 %2)
或#(applicative/fapply (applicative/pure %1) %2)
。然而,这种解决方案闻起来像是在欺骗一个clojure型系统。
第二个解决方案是定义一个宏extend-applicative
,它将自动实现Functor
协议。但是这个解决方案看起来并不好看,因为它需要来自库用户的额外工作,并且它允许对functor / applicative实例进行sepparate定义,这很容易导致错误。
有没有更好的方法在clojure中表达这种关系?
答案 0 :(得分:2)
请记住,extend
并不要求被扩展的类型是具体实现; 一个协议可以扩展另一个你也可以扩展接口和抽象类。你应该可以做类似
(ns protocol.applicative)
(defprotocol Applicative
(fapply [f g])
(pure [x] ))
(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。希望能帮助你实现目标。