bst*_*our 16 monads haskell functor applicative
这是一个普遍的问题,与任何一段代码无关.
假设您有一个T a可以给出实例的类型Monad.由于每个单子是Applicative通过分配pure = return和(<*>) = ap,然后每一个应用性是Functor通过fmap f x = pure f <*> x,是它更好地定义你的情况Monad,然后再平凡给出T的实例Applicative和Functor?
对我来说感觉有点落后.如果我在做数学而不是编程,我会认为我会先显示我的对象是一个仿函数,然后继续添加限制,直到我也将它显示为monad.我知道Haskell只是受到类别理论的启发,显然在构建证明时使用的技术不是编写有用程序时会使用的技术,但我想从Haskell社区获得意见.从Monad下往上更好Functor吗?或从Functor最多Monad?
J. *_*son 25
我倾向于编写并Functor首先编写实例.这是因为如果你使用LANGUAGE DeriveFunctorpragma,那么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
Run Code Online (Sandbox Code Playgroud)
上面我按顺序定义了实例,并且Functor单独Monad考虑每个实例都是正确的.不幸的是,Applicative和Monad实例并不一致:ap和(<*>)是因为是观察地不同的(>>)和(*>).
Err "hi" <*> Err "bye" == Err "hibye"
Err "hi" `ap` Err "bye" == Err "hi"
Run Code Online (Sandbox Code Playgroud)
出于敏感目的,特别是一旦申请人/ Monad提案在每个人手中,这些都应该一致.如果您定义了,instance Applicative (Err e) where { pure = return; (<*>) = ap }那么它们将对齐.
但是,最后,你可能能够仔细地区分差异Applicative并使Monad它们以良性的方式表现出不同的行为 - 比如拥有一个更懒惰或更有效的Applicative实例.这实际上经常发生,我觉得陪审团仍然对"良性"意味着什么以及你的实例应该在什么样的"观察"下进行一点点.也许最合理的一些用途是在Facebook的Haxl项目中,Applicative实例比实例更加并行化Monad,因此以一些相当严重的"未观察到的"副作用为代价更有效.
无论如何,如果它们不同,请记录下来.
与Abrahamson的回答相比,我经常选择反向方法.我手动定义了Monad实例,Applicative并Functor在其中使用已经定义的函数来定义和使用它Control.Monad,这使得这些实例对于绝对任何monad都是相同的,即:
instance Applicative SomeMonad where
pure = return
(<*>) = ap
instance Functore SomeMonad where
fmap = liftM
Run Code Online (Sandbox Code Playgroud)
虽然这种方式定义Functor并且Applicative始终是"无脑"并且很容易推理,但我必须注意,这不是最终的解决方案,因为有些情况下,实例可以更有效地实现甚至提供新功能.例如,Applicative实例Concurrently执行的事......同时,而Monad实例只能按顺序执行这些由于自然单子.
| 归档时间: |
|
| 查看次数: |
1359 次 |
| 最近记录: |