gpt4 book ai didi

haskell - 组合 Monad 与应用仿函数

转载 作者:行者123 更新时间:2023-12-02 23:33:10 25 4
gpt4 key购买 nike

TypeclassopediaMonad Transformers 部分解释:

Unfortunately, monads do not compose as nicely as applicative functors (yet another reason to use Applicative if you don’t need the full power that Monad provides)

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

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

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

我读了这个answer ,但是你能举个例子来帮助我理解吗?

最佳答案

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

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一个fmap -ed f我们可以将它通过各层 fg就像我们需要的那样。类似的游戏可以用 pure 来玩。

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

同时(<*>)看起来很棘手,如果你仔细看的话,这与我们在 fmap 上使用的技巧完全相同。和pure .

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

在所有情况下,我们都可以将我们需要的运算符“穿过” f 的各层和g正如我们所希望的那样。

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

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

使用

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)

此时问题所在可能已经很清楚了——我们只知道如何连接 f连续层或g s,但在这里我们看到它们交织。你会发现我们需要一个交换性属性

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
<小时/>

那么这一切的结果是什么呢? Applicative 总是 Compose ,但是Monad 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 )

关于haskell - 组合 Monad 与应用仿函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29453915/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com