这是一个一般性问题,与任何一段代码无关。
假设你有一个类型T a
可以给出一个实例Monad
。因为每个单子都是一个Applicative
通过分配pure = return
and (<*>) = ap
,然后每个应用程序都是一个Functor
via fmap f x = pure f <*> x
,定义你的实例是否更好Monad
首先,然后简单地给出T
的实例Applicative
and Functor
?
对我来说感觉有点落后。如果我做数学而不是编程,我会认为我会首先证明我的对象是一个函子,然后继续添加限制,直到我也证明它是一个单子。我知道 Haskell 只是受到范畴论的启发,显然,构建证明时使用的技术并不是编写有用程序时使用的技术,但我想从 Haskell 社区获得意见。是不是比较好从Monad
向下Functor
?或来自Functor
up to Monad
?
我倾向于写和看写的Functor
先实例。加倍如此,因为如果你使用LANGUAGE DeriveFunctor
那么编译指示data Foo a = Foo a deriving ( Functor )
大部分时间都在工作。
棘手的部分是当你的实例达成一致时Applicative
可以比你的更笼统Monad
。例如,这是一个Err
数据类型
data Err e a = Err [e] | Ok a deriving ( Functor )
instance Applicative (Err e) where
pure = Ok
Err es <*> Err es' = Err (es ++ es')
Err es <*> _ = Err es
_ <*> Err es = Err es
Ok f <*> Ok x = Ok (f x)
instance Monad (Err e) where
return = pure
Err es >>= _ = Err es
Ok a >>= f = f a
上面我定义了实例Functor
-to-Monad
顺序,并且单独来看,每个实例都是正确的。不幸的是,Applicative
and Monad
实例不对齐:ap
and (<*>)
明显不同(>>)
and (*>)
.
Err "hi" <*> Err "bye" == Err "hibye"
Err "hi" `ap` Err "bye" == Err "hi"
出于敏感性目的,特别是当 Applicative/Monad 提案掌握在每个人手中时,这些应该保持一致。如果你定义了instance Applicative (Err e) where { pure = return; (<*>) = ap }
然后他们will align.
但最后,你可能能够仔细地梳理出不同之处Applicative
and Monad
这样他们就会以良性的方式表现得不同——比如有一个更懒惰或更高效的人Applicative
实例。这种情况实际上经常发生,我觉得陪审团对于“良性”的含义以及您的实例应该在什么样的“观察”下保持一致还有些不明确。也许对此最广泛的使用是在 Facebook 的 Haxl 项目中,其中Applicative
实例是更加并行化比Monad
例如,因此效率更高,但代价是一些相当严重的“未观察到的”副作用。
无论如何,如果它们不同,请记录下来。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)