Monad比Applicative更强大? [英] Monad more powerful than Applicative?
问题描述
我查看了过去的讨论,但看不到为什么的答案其实是正确的。
应用程式
< * GT; :: f(a - > b) - > f a - > fb
Monad
(>> =):: ma - > (a - > m b) - > mb
所以如果我弄清楚了,声称是>> =
不能通过假设存在<>
来完成。那么,让我们假设我有< * GT;
。
我想创建>> =
。
所以我有 fa
。
我有 f(a - > ; b)
。
现在看看它, f(a - > b)
可以写成(a - > b)
(如果某物是x,y,z的函数 - 那么它也是x,y的函数)。 b $ b
因此,从<>
的存在,我们得到(a - > b) - > f a - > (a→b)→f a)→f b 可以再次写成
fb
,可以写成(a - > fb)
。
所以我们有 fa
,我们有(a - > fb)
,我们知道< />
结果为 fb
,所以我们得到:
fa - > (a - > f b) - > fb
这是一个单子。
实际上,在一种更直观的语言:在执行< *>
时,我从<$ c $中提取(a - > b)
c> f(a - > b),我从 fa
中提取 a
,然后在 a
上应用(a - > b)
,并获得 b
我用 f
包装,最后得到 fb
。 所以我几乎一样创建>> =
。在 a
上应用(a - > b)
并获得 b $ c后$ c>,再做一步,用
f
包装它,所以我返回 fb
,因此我知道我有一个函数(a - > fb)
。
现在看看它,可以将
f(a - > b)
写成(a - > b)
没有。它不能。在这一点上,你的直觉是(危险的)遥远。这就像说锤子非常适合驱动螺丝钉一样,因为它已经适用于指甲*。您不能简单地在这里放置 f
,它是**类型的一部分。
取而代之,事实是直的。一个 Applicative
有三个相关函数,计数 Functor
的 fmap
:
fmap :: Functor f => (a - > b) - > f a - > f b
pure :: Applicative f => a - > f a
(*)::适用的f => f(a - > b) - > f a - > fb
以下是另一个事实:您可以定义绑定((>> =)
)以加入
,反之亦然:
join :: Monad m => m(m a) - > m a
join k = k>> = id
(>> =):: Monad m => m a - > (a - > m b) - > mb
k>> = f = join(fmap fk)
是连接和绑定的实现,这里提供的是Monad定义的一部分,还是仅连接和绑定Monad定义的签名部分? [...]现在我问自己为什么他们会打扰。
这些不是官方的定义,因为它们永远不会终止。你必须为你的类型定义(>> =)
,如果你想使它成为一个单子:
instance Monad YourType其中
k>> = f = ...
另外,您的连接定义使用的ID不在Monad接口中,为什么它在数学上是合法的?
首先, id :: a - >一个
被定义为任何类型。其次,monad的数学定义实际上是通过 join
。所以它更合法。但最重要的是,我们可以根据 join
(练习)定义monad法则。
如果我们创建加入
通过 Applicative
,我们也可以创建绑定。如果我们不能通过 Applicative
方法创建 join
,那么我们也不能派生 bind $ c> $ C>。并且
join
的类型实际上很明显我们不能从 Applicative
中派生它:
join:Monad m => m(m a) - > ma
- ^ ^ ^
加入可以放弃其中一个 m
图层。让我们来看看是否可以在其他方法中做同样的事情:
fmap :: Functor f => (a - > b) - > f a - > fb
^ ^
0 here here 1
pure :: Applicative f => a - > f a
^ | ^
0在这里| 1 here
(< ; *>):: Applicative f => f(a - > b) - > f a - > fb
^ ^
1 here 1
答案是no:none我们通过 Applicative
给出的工具使我们能够将多个 m
合并为一个工具。这也正是在另一个问题的引用段落之后写在 Typeclassopedia 中的内容:
为了从不同的角度看待Monad增加的功能,让我们看看如果我们试图实现
(>> =)
,以fmap
,纯
和(小于* GT)
。我们给出ma 类型的值 x
,并且函数k
类型a - > m b
,所以我们唯一能做的就是将k
应用于x
。当然,我们不能直接应用它。我们必须使用fmap
来取代m
。但是fmap k
的类型是什么?那么,它是m a - > m(m b)
。因此,在我们将它应用于x
之后,我们剩下一些类型m(mb)
- 但现在我们卡住;我们真正想要的是m b
,但是没有办法从这里到达。我们可以使用pure
添加m
,但我们无法折叠多个m
合并为一个。
请注意加入
不能完全摆脱 m
,这将是一个完全提取,而—取决于其他一些函数— comonad 。无论如何,确保你不会让你的直觉走向歧途;信任和使用类型。
*这种比较有点不好,因为您实际上可以尝试用锤子将螺钉拧入一块木。所以想想要一个塑料螺丝钉,一个橡胶锤子和一个碳钢板,你要把它钉在里面。祝你好运。 那么,你可以放弃它,但是类型会发生巨大的变化。 ***鉴于 I looked at past discussion but could not see why any of the answers are actually correct. Applicative Monad So if I get it right, the claim is that Well, let's assume I have And I want to create So I have I have Now when you look at it, So from the existence of So we have which is a monad. Actually, in a more intuitive language: when implementing So I do almost the same to create Now when you look at it, No. It can't. Your intuition is (dangerously) far off at this point. That's like saying a hammer is perfect for driving screws in, since it already works for a nail*. You can't simply drop Instead, let's get the facts straight. An Here's another fact: you can define bind (
are the implementations of join and bind you provided here part of the Monad definition, or are only join and bind signatures part of the Monad definition? [...] So now I ask myself why would they bother. Those aren't the official definitions of course, since they would never terminate. You have to define
Also, your join definition uses id which is not in the Monad interface, why is it mathematically legitimate? First of all, If we created Join is able to drop one of the
The answer is no: none of the tools we're given by To see the increased power of Monad from a different point of view, let’s see what happens if we try to implement Note that * That comparison is a little bit bad, because you could actually try to dive a screw in with a hammer into a piece of wood. So think of a plastic screw, a rubber hammer and a carbon steel plate you want to drive the nail in. Good luck. ** Well, you can drop it, but then the type changes drastically. *** Given that 这篇关于Monad比Applicative更强大?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
(> > =)
和 join
等于权力,任何(>> =)
使用公式可以使用 join
转换为一个,它们当然都是数学声音。 <*> :: f (a -> b) -> f a -> f b
(>>=) :: m a -> (a -> m b) -> m b
>>=
cannot be written by only assuming the existence of <*>
<*>
. >>=
.f a
.f (a -> b)
. f (a -> b)
can be written as (a -> b)
(if something is a function of x, y , z - then it's also a function of x, y).<*>
we get (a -> b) -> f a -> f b
which again can be written as ((a -> b) -> f a) -> f b
, which can be written as (a -> f b)
.f a
, we have (a -> f b)
, and we know that <*>
results in f b
, so we get:f a -> (a -> f b) -> f b
<*>
, I extract (a -> b)
out of f(a -> b)
, I extract a
out of f a
, and then I apply (a -> b)
on a
and get b
which I wrap with f
to finally get f b
.>>=
. After applying (a -> b)
on a
and getting b
, do one more step and wrap it with f
, so I return f b
, hence I know I have a function (a -> f b)
.
f(a -> b)
can be written as (a -> b)
f
here, it's part of the type**.Applicative
has three associated functions, counting Functor
's fmap
:fmap :: Functor f => (a -> b) -> f a -> f b
pure :: Applicative f => a -> f a
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(>>=)
) in terms of join
and vice versa:join :: Monad m => m (m a) -> m a
join k = k >>= id
(>>=) :: Monad m => m a -> (a -> m b) -> m b
k >>= f = join (fmap f k)
(>>=)
for your type if you want to make it a a monad:instance Monad YourType where
k >>= f = ...
id :: a -> a
is defined for any type. Second, the mathematical definition of a monad is actually via join
. So it's "more"*** legitimate. But most important of all, we can define the monad laws in terms of join
(exercise).join
via Applicative
, we could also create bind. If we cannot create join
via Applicative
methods, neither can we derive bind
. And join
's type actually makes it obvious that we cannot derive it from Applicative
:join :: Monad m => m (m a) -> m a
-- ^ ^ ^
m
layers. Let's check whether it's possible to do the same in the other methods:fmap :: Functor f => (a -> b) -> f a -> f b
^ ^
0 here 1 here
pure :: Applicative f => a -> f a
^ | ^
0 here | 1 here
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
^ ^
1 here 1 here
Applicative
enables us collapse multiple m
's into a single one. And that's also what is written in the Typeclassopedia right after the cited paragraph in the other question:
(>>=)
in terms of fmap
, pure
, and (<*>)
. We are given a value x
of type m a
, and a function k
of type a -> m b
, so the only thing we can do is apply k
to x
. We can’t apply it directly, of course; we have to use fmap
to lift it over the m
. But what is the type of fmap k
? Well, it’s m a -> m (m b)
. So after we apply it to x
, we are left with something of type m (m b)
—but now we are stuck; what we really want is an m b
, but there’s no way to get there from here. We can add m
’s using pure
, but we have no way to collapse multiple m
’s into one.join
doesn't make it possible to get rid of m
completely, that would be a total extraction, and—depending on some other functions—a feature of a comonad. Either way, make sure that you don't let your intuition go astray; trust and use the types.(>>=)
and join
are equivalent of power and any (>>=)
using formula can be transformed to one only using join
, they are of course both mathematical sound.