根据Monad的应用定义Functor是更好的,反之亦然? [英] Is it better to define Functor in terms of Applicative in terms of Monad, or vice versa?
问题描述
这是一个普遍的问题,与任何一段代码无关。
假设你有一个类型 T a
可以给出一个 Monad
的实例。由于每个monad通过分配 pure = return
和(< *>),所以是
Applicative )= ap
,然后每个应用程序通过 fmap fx = pure f * c>来获得
,先定义 Functor
x Monad
的实例,然后再给出 T
> Applicative
和 Functor
?
的实例有点落后于我。如果我在做数学而不是编程,我会认为我会首先证明我的对象是一个函数,然后继续添加限制,直到我还将它展示为monad。我知道Haskell只是受到了类别理论的启发,显然当构建证明时使用的技术并不是编写有用程序时使用的技术,但我希望从Haskell社区获得意见。从 Monad
下降到 Functor
是否更好?或从 Functor
到 Monad
?
我倾向于编写并首先写入 Functor
实例。因为如果您使用 LANGUAGE DeriveFunctor
编译指示,那么数据Foo a = Foo a派生(Functor)
当你的 Applicative
可以比你的<$ $更普遍时C $ C>单子。例如,这是一个 Err
数据类型
数据Err ea = Err [e] |确定一个派生函数(Functor)
实例(Err e)其中
pure = Ok
Err es< *> Err es'= Err(es ++ es')
Err es< *> _ =错误
_< *> Err es = Err es
Ok f <*> Ok x = Ok(fx)
实例Monad(Err e)其中
return =纯
错误>> = _ =错误
Ok a >> = f = fa
上面我定义了 Functor
-to - Monad
顺序,并且单独采用每个实例都是正确的。不幸的是, Applicative
和 Monad
实例不符合: ap
和(*)
与(>>)
和<$ c明显不同$ c $($>)。
Errhi*< Errbye== Errhibye
Errhi`ap` Errbye== Errhi
为了达到敏感目的,特别是一旦申请人/单体提案在大家手中,这些应该一致。如果您定义了实例Applicative(Err e),其中{pure = return; (< *>)= ap}
然后他们将对齐。然后,最后,你可能能够仔细地分开 Applicative
和 Monad
中的区别,以便它们在良性方面表现不同 - 例如具有更简单或更高效的 Applicative
实例。这实际上发生得相当频繁,我觉得陪审团对于良性意味着什么以及在你的实例应该对齐什么类型的观察下仍然存在一些问题。也许一些最合群的用法是在Facebook的Haxl项目中, Applicative
实例比 > Monad
实例,因此以一些相当严重的未观察到的副作用为代价,效率更高。
无论如何,if他们不同,记录它。
This is a general question, not tied to any one piece of code.
Say you have a type T a
that can be given an instance of Monad
. Since every monad is an Applicative
by assigning pure = return
and (<*>) = ap
, and then every applicative is a Functor
via fmap f x = pure f <*> x
, is it better to define your instance of Monad
first, and then trivially give T
instances of Applicative
and Functor
?
It feels a bit backward to me. If I were doing math instead of programming, I would think that I would first show that my object is a functor, and then continue adding restrictions until I have also shown it to be a monad. I know Haskell is merely inspired by Category Theory and obviously the techniques one would use when constructing a proof aren't the techniques one would use when writing a useful program, but I'd like to get an opinion from the Haskell community. Is it better to go from Monad
down to Functor
? or from Functor
up to Monad
?
I tend to write and see written the Functor
instance first. Doubly so because if you use the LANGUAGE DeriveFunctor
pragma then data Foo a = Foo a deriving ( Functor )
works most of the time.
The tricky bits are around agreement of instances when your Applicative
can be more general than your Monad
. For instance, here's an Err
data type
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
Above I defined the instances in Functor
-to-Monad
order and, taken in isolation, each instance is correct. Unfortunately, the Applicative
and Monad
instances do not align: ap
and (<*>)
are observably different as are (>>)
and (*>)
.
Err "hi" <*> Err "bye" == Err "hibye"
Err "hi" `ap` Err "bye" == Err "hi"
For sensibility purposes, especially once the Applicative/Monad Proposal is in everyone's hands, these should align. If you defined instance Applicative (Err e) where { pure = return; (<*>) = ap }
then they will align.
But then, finally, you may be capable of carefully teasing apart the differences in Applicative
and Monad
so that they behave differently in benign ways---such as having a lazier or more efficient Applicative
instance. This actually occurs fairly frequently and I feel the jury is still a little bit out on what "benign" means and under what kinds of "observation" should your instances align. Perhaps some of the most gregarious use of this is in the Haxl project at Facebook where the Applicative
instance is more parallelized than the Monad
instance, and thus is far more efficient at the cost of some fairly severe "unobserved" side effects.
In any case, if they differ, document it.
这篇关于根据Monad的应用定义Functor是更好的,反之亦然?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!