Nir*_*n M 11 monads haskell composition monad-transformers
当我Composing Types从Haskell Book 学习章节时,我被赋予编写以下类型的Functor和Applicative实例的任务。
newtype Compose f g a = Compose { getCompose :: f (g a) }
Run Code Online (Sandbox Code Playgroud)
我写了以下定义
fmap f (Compose fga) = Compose $ (fmap . fmap) f fga
Run Code Online (Sandbox Code Playgroud)
(Compose f) <*> (Compose a) = Compose $ (<*>) <$> f <*> a
Run Code Online (Sandbox Code Playgroud)
我了解到,组成两个Functor或Applicatives分别会给Functor和Applicative。
作者还解释说,不可能以相同的方式组成两个Monad。因此,我们使用Monad变形金刚。我只是不想阅读Monad Transformers,除非我清楚为什么Monad不作曲。
到目前为止,我尝试编写如下bind函数:
(>>=) :: Compose f g a -> (a -> Compose f g b) -> Compose f g b
(Compose fga) >>= h = (fmap.fmap) h fga
Run Code Online (Sandbox Code Playgroud)
当然从GHC得到了这个错误
预期类型:撰写fgb
实际类型:f(g(合成fgb))
如果我能f g以某种方式去除最外面的东西,那么构图可以给我们一个单子,对吗?(尽管如此,我仍然不知道该如何去除)
我试着阅读从其他堆栈溢出的问题,如答案这个,但所有的答案是更多的理论或一些数学。我仍然不知道为什么Monads不作曲。有人可以不使用数学就向我解释吗?
小智 19
我认为通过查看join运算符最容易理解这一点:
join :: Monad m => m (m a) -> m a
Run Code Online (Sandbox Code Playgroud)
join是>>=定义的替代方法Monad,并且推理起来稍微容易一些。(但是,现在你有一个运动要做到:展示如何实现>>=从join,以及如何实现join从>>=!)
让我们尝试进行join操作Composed f g,看看出了什么问题。我们的输入实质上是type的值f (g (f (g a))),并且我们想产生type的值f (g a)。我们也知道我们分别拥有joinfor f和g,因此,如果我们可以获取type的值f (f (g (g a))),那么我们可以将其与fmap join . join获得f (g a)所需的值联系起来。
现在,f (f (g (g a)))是不是这样从远处f (g (f (g a)))。我们真正需要的只是一个像这样的函数:distribute :: g (f a) -> f (g a)。然后我们可以join像这样实现:
join = Compose . fmap join . join . fmap (distribute . fmap getCompose) . getCompose
Run Code Online (Sandbox Code Playgroud)
注意:distribute为了确保join我们到达这里的合法性,我们需要满足一些法律。
好的,这表明如果我们有分配律, 我们如何组成两个单子distribute :: (Monad f, Monad g) => g (f a) -> f (g a)。现在,它可能是每对单子有分配律是真实的。也许我们只需要认真思考如何写下一个?
不幸的是,有一些没有分配律的单子。因此,我们可以通过生成两个绝对不能将a g (f a)变为a的单子来回答您的原始问题f (g a)。这两个单子将见证一个事实,即单子通常不组成。
我主张g = IO并且f = Maybe没有分配法
-- Impossible!
distribute :: IO (Maybe a) -> Maybe (IO a)
Run Code Online (Sandbox Code Playgroud)
让我们考虑一下为什么这样的事情应该是不可能的。此功能的输入是IO动作,该动作进入现实世界并最终产生Nothing或Just x。该函数的输出是Nothing,或者Just是IO操作,在运行时最终会产生x。要产生Maybe (IO a),我们将不得不窥视未来并预测IO (Maybe a)将要采取的行动!
综上所述:
g (f a) -> f (g a)。