组合 Monad 与应用函子

2024-03-06

The 类型分类百科全书 https://wiki.haskell.org/Typeclassopedia's 莫纳德变形金刚部分解释:

不幸的是,Monad 的组合不如 Applicative 函子(如果您不需要 Monad 提供的全部功能,这也是使用 Applicative 的另一个原因)

查看类型>>= and <*>,上面的说法我不太清楚。

(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(>>=) :: Monad m => m a -> (a -> m b) -> m b

请解释一下“单子的组合不如应用函子那么好”。

我读了这个answer https://stackoverflow.com/questions/7040844/applicatives-compose-monads-dont,但是你能举个例子来帮助我理解吗?


种类的类型有多种概念* -> *可能会“组成”。更重要的是你可以“按顺序”组合它们。

newtype Compose f g x = Compose { getCompose :: f (g x) }

在这里你可以看到Compose有善良(* -> *) -> (* -> *) -> (* -> *)就像任何好的函子组合应该做的那样。

那么问题来了:是否存在像下面这样的守法案例?

instance (Applicative f, Applicative g) => Applicative (Compose f g)
instance (Monad f,       Monad g)       => Monad       (Compose f g)

关于为什么 monad 的组合不如应用程序的简短答案是,虽然第一个实例可以编写,但第二个实例不能。咱们试试吧!


我们可以热身Functor

instance (Functor f,     Functor g)     => Functor     (Compose f g) where
  fmap f (Compose fgx) = Compose (fmap (fmap f) fgx)

在这里我们看到了这一点,因为我们可以fmap an fmap-ed f我们可以通过层传递它f and g就像我们需要的那样。玩类似的游戏pure

instance (Applicative f, Applicative g) => Applicative (Compose f g) where
  pure a = Compose (pure (pure a))

而同时(<*>)看起来很棘手,如果你仔细看的话,这与我们对两者使用的技巧完全相同fmap and pure.

  Compose fgf <*> Compose fgx = Compose ((<*>) <$> fgf <*> fgx)

在所有情况下,我们都可以推动我们需要的操作符“穿过”各个层f and g正如我们所希望的那样。

但现在让我们看一下Monad。而不是试图定义Monad via (>>=),我将通过以下方式工作join。实施Monad我们需要实施

join :: Compose f g (Compose f g x) -> Compose f g x

using

join_f :: f (f x) -> f x  -- and
join_g :: g (g x) -> g x

或者,如果我们剥离newtype噪音,我们需要

join :: f (g (f (g x))) -> f (g x)

至此问题可能就清楚了——我们只知道如何加入连续的层数fs or gs,但在这里我们看到了它们交织在一起。你会发现我们需要一个交换律财产

class Commute f g where
  commute :: g (f x) -> f (g x)

现在我们可以实施

instance (Monad f, Monad g, Commute f g) => Monad (Compose f g)

与(的newtype不可知论者)join定义为

join :: f (g (f (g x))) -> f (g x)
join fgfgx = fgx where
  ffggx :: f (f (g (g x)))
  ffggx = fmap commute fgfgx
  fggx :: f (g (g x))
  fggx = join_f ffggx
  fgx :: f (g x)
  fgx = fmap join_g fggx

那么这一切的结果是什么呢?Applicatives always Compose, but Monads Compose仅当它们的层数Commute.

我们什么时候可以commute层?这里有些例子

instance Commute ((->) x) ((->) y) where
  commute = flip

instance Commute ((,) x) ((,) y) where
  commute (y, (x, a)) = (x, (y, a))

instance Commute ((->) x) ((,) y) where
  commute (y, xa) = \x -> (y, xa x)

-- instance Commute ((,) x) ((->) y) does not exist; try to write yourself!
--
-- OR:
-- It turns out that you need to somehow "travel back in time" to make it
-- work...
-- 
-- instance Commute ((,) x) ((->) y) where
--   commute yxa = ( ..., \y -> let (x, a) = yxa y in a )
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

组合 Monad 与应用函子 的相关文章

随机推荐