* *如何衍生自pure和(>> =)? [英] How does <*> derived from pure and (>>=)?

查看:55
本文介绍了* *如何衍生自pure和(>> =)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

(<*>)可以从pure和(>>=)派生:

(<*>) can be derived from pure and (>>=):

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

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

我对>>=的用法感到困惑.我认为这需要一个函子f a和一个函数,然后返回另一个函子f b.但是在这种表达中,我感到迷茫.

I am confused by the usage of >>=. I think it takes a functor f a and a function, then return another functor f b. But in this expression, I feel lost.

推荐答案

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

Lets start with the type we're implementing:

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

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

(The normal type of <*> of course has an Applicative constraint, but here we're trying to use Monad to implement Applicative)

因此,在fs <*> as = _中,fs是"f of functions"(f (a -> b)),而as是"f of a s".

So in fs <*> as = _, fs is an "f of functions" (f (a -> b)), and as is an "f of as".

我们将从绑定fs开始:

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

如果您实际进行编译,GHC会告诉我们孔(_)的类型:

If you actually compile that, GHC will tell us what type the hole (_) has:

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

这很有道理. Monad的>>=在左边带一个f a,在右边带一个函数a -> f b,因此,通过在左边绑定一个f (a -> b),右边的函数将接收到一个(a -> b)从提取"的函数. c10>.并且只要我们可以编写一个可以使用该函数返回f b的函数,则整个绑定表达式将返回我们需要满足<*>的类型签名的f b.

That makes sense. Monad's >>= takes an f a on the left and a function a -> f b on the right, so by binding an f (a -> b) on the left the function on the right gets to receive an (a -> b) function "extracted" from fs. And provided we can write a function that can use that to return an f b, then the whole bind expression will return the f b we need to meet the type signature for <*>.

因此它看起来像:

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

我们在那里可以做什么?我们有f :: a -> b,而我们仍然有as :: f a,我们需要制作一个f b.如果您习惯了Functor,这是显而易见的.只是fmap f as. Monad表示Functor,因此实际上可以正常工作:

What can we do there? We've got f :: a -> b, and we've still got as :: f a, and we need to make an f b. If you're used to Functor that's obvious; just fmap f as. Monad implies Functor, so this does in fact work:

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

我认为,这也是一种的更容易理解的方法,用于理解可以使用Monad的功能来通用实现Applicative的方式.

It's also, I think, a much easier way to understand the way Applicative can be implemented generically using the facilities from Monad.

那么为什么您的示例是使用另一个>>=pure而不是仅仅使用fmap编写的?这回想起Monad ApplicativeFunctor作为超类的日子. Monad总是道德上"暗示这两者(因为您只能使用Monad的功能实现ApplicativeFunctor),但是Haskell并不总是要求有这些实例,这导致了书本的产生. ,教程,博客文章等,它们解释了如何仅使用Monad来实现这些方法.给出的示例行只是根据>>=pure(return) 1 内联fmap的定义.

So why is your example written using another >>= and pure instead of just fmap? It's kind of harkening back to the days when Monad did not have Applicative and Functor as superclasses. Monad always "morally" implied both of these (since you can implement Applicative and Functor using only the features of Monad), but Haskell didn't always require there to be these instances, which leads to books, tutorials, blog posts, etc explaining how to implement these using only Monad. The example line given is simply inlining the definition of fmap in terms of >>= and pure (return)1.

我将继续打开包装,好像我们没有fmap一样,这样它会导致您感到困惑.

I'll continue to unpack as if we didn't have fmap, so that it leads to the version you're confused by.

如果我们不打算使用fmap来组合f :: a -> bas :: f a,那么我们将需要绑定as,以便我们具有类型为a的表达式来应用f到:

If we're not going to use fmap to combine f :: a -> b and as :: f a, then we'll need to bind as so that we have an expression of type a to apply f to:

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

在该孔内,我们需要制作一个f b,我们有f :: a -> ba :: a. f a给我们一个b,所以我们需要调用pure将其转换为f b:

Inside that hole we need to make an f b, and we have f :: a -> b and a :: a. f a gives us a b, so we'll need to call pure to turn that into an f b:

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

这就是这行的内容.

  1. 绑定fs :: f (a -> b)以访问f :: a -> b
  2. 在有权访问f的函数中,它绑定as以获得对a :: a
  3. 的访问权
  4. 在有权访问a的函数内(该函数仍在有权访问f的函数内),调用f a生成b,然后在结果上调用pure使其成为f b
  1. Binding fs :: f (a -> b) to get access to an f :: a -> b
  2. Inside the function that has access to f it's binding as to get access to a :: a
  3. Inside the function that has access to a (which is still inside the function that has access to f as well), call f a to make a b, and call pure on the result to make it an f b


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


1 You can implement fmap using >>= and pure as fmap f xs = xs >>= (\x -> pure (f x)), which is also fmap f xs = xs >>= pure . f. Hopefully you can see that the inner bind of your example is simply inlining the first version.

这篇关于* *如何衍生自pure和(&gt;&gt; =)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆