* *如何衍生自pure和(>> =)? [英] How does <*> derived from pure and (>>=)?
问题描述
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 a
s".
我们将从绑定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
没 将Applicative
和Functor
作为超类的日子. Monad
总是道德上"暗示这两者(因为您只能使用Monad
的功能实现Applicative
和Functor
),但是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 -> b
和as :: 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 -> b
和a :: 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)))
这就是这行的内容.
- 绑定
fs :: f (a -> b)
以访问f :: a -> b
- 在有权访问
f
的函数中,它绑定as
以获得对a :: a
的访问权
- 在有权访问
a
的函数内(该函数仍在有权访问f
的函数内),调用f a
生成b
,然后在结果上调用pure
使其成为f b
- Binding
fs :: f (a -> b)
to get access to anf :: a -> b
- Inside the function that has access to
f
it's bindingas
to get access toa :: a
- Inside the function that has access to
a
(which is still inside the function that has access tof
as well), callf a
to make ab
, and callpure
on the result to make it anf 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和(>> =)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!