gpt4 book ai didi

haskell - <*> 如何从 pure and (>>=) 派生出来?

转载 作者:行者123 更新时间:2023-12-02 17:55:59 26 4
gpt4 key购买 nike

class Applicative f => Monad f where
return :: a -> f a
(>>=) :: f a -> (a -> f b) -> f b

(<*>)可以从纯和 (>>=) 导出:

fs <*> as =
fs >>= (\f -> as >>= (\a -> pure (f a)))

对于行

fs >>= (\f -> as >>= (\a -> pure (f a)))

我对 >>= 的用法感到困惑。我认为这需要一个仿函数 f a和一个函数,然后返回另一个仿函数 f b 。但在这个表情中,我却感到失落。

最佳答案

让我们从我们正在实现的类型开始:

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

(普通类型 <*> 当然有 Applicative 约束,但这里我们尝试使用 Monad 来实现 Applicative )

所以在 fs <*> as = _ , fs是“函数 f”( f (a -> b) ),并且 as是“a s 的 f”。

我们将从绑定(bind) fs 开始:

(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= _

如果您实际编译它,GHC 将告诉我们该洞 ( _ ) 的类型:

foo.hs:4:12: warning: [-Wtyped-holes]
• Found hole: _ :: (a -> b) -> f b
Where: ‘a’, ‘f’, ‘b’ are rigid type variables bound by
the type signature for:
(Main.<*>) :: forall (f :: * -> *) a b.
Monad f =>
f (a -> b) -> f a -> f b
at foo.hs:2:1-45

这是有道理的。莫纳德的>>=需要 f a左边有一个函数a -> f b在右侧,因此通过绑定(bind) f (a -> b)左边的函数右边的函数会收到 (a -> b)函数“提取”自 fs 。假设我们可以编写一个函数,可以使用它返回 f b ,那么整个绑定(bind)表达式将返回 f b我们需要满足 <*> 的类型签名.

所以它看起来像:

(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> _)

我们能在那里做什么?我们有f :: a -> b ,我们仍然有 as :: f a ,我们需要制作一个 f b 。如果您习惯 Functor这是显而易见的;只是fmap f asMonad意味着Functor ,所以这实际上是有效的:

(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> fmap f as)

我认为,这也是一种更容易理解 Applicative 的方法。一般可以使用 Monad 中的设施来实现.

那么为什么你的示例是使用另一个 >>= 编写的和pure而不仅仅是fmap ?这有点让人回想起 Monad 的日子。 没有ApplicativeFunctor作为父类(super class)。 Monad总是“道德上”暗示这两者(因为您可以仅使用 Applicative 的功能来实现 FunctorMonad ),但 Haskell 并不总是要求存在这些实例,这导致了书籍,教程,博客文章等解释如何仅使用Monad来实现这些。给出的示例行只是内联 fmap 的定义。就>>=而言和pure ( return )1

我将继续拆包,就好像我们没有 fmap 一样,这样它就会导致您感到困惑的版本。

如果我们不打算使用fmap结合f :: a -> bas :: f a ,那么我们需要绑定(bind)as这样我们就有了 a 类型的表达式申请f至:

(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> as >>= (\a -> _))

在那个洞里我们需要做一个 f b ,我们有f :: a -> ba :: af a给我们一个b ,所以我们需要调用pure将其变成 f b :

(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> as >>= (\a -> pure (f a)))

这就是这条线正在做的事情。

  1. 绑定(bind)fs :: f (a -> b)访问 f :: a -> b
  2. 在有权访问 f 的函数内它具有约束力as访问 a :: a
  3. 在有权访问 a 的函数内(它仍然在可以访问 f 的函数内部),调用 f a制作 b ,并调用pure结果使其成为 f b
<小时/>

1 您可以实现 fmap使用>>=purefmap f xs = xs >>= (\x -> pure (f x)) ,这也是fmap f xs = xs >>= pure . f 。希望您可以看到示例的内部绑定(bind)只是内联第一个版本。

关于haskell - <*> 如何从 pure and (>>=) 派生出来?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51960848/

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