Monad比Applicative更强大? [英] Monad more powerful than Applicative?

查看:88
本文介绍了Monad比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 ,再做一步,用 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>。并且 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 。无论如何,确保你不会让你的直觉走向歧途;信任和使用类型。



*这种比较有点不好,因为您实际上可以尝试用锤子将螺钉拧入一块木。所以想想要一个塑料螺丝钉,一个橡胶锤子和一个碳钢板,你要把它钉在里面。祝你好运。 那么,你可以放弃它,但是类型会发生巨大的变化。

***鉴于(> > =) join 等于权力,任何(>> =)使用公式可以使用 join 转换为一个,它们当然都是数学声音。


I looked at past discussion but could not see why any of the answers are actually correct.

Applicative

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

Monad

(>>=) :: m a -> (a -> m b) -> m b

So if I get it right, the claim is that >>= cannot be written by only assuming the existence of <*>

Well, let's assume I have <*>.

And I want to create >>=.

So I have f a.

I have f (a -> b).

Now when you look at it, 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).

So from the existence of <*> 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).

So we have 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

which is a monad.

Actually, in a more intuitive language: when implementing <*>, 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.

So I do almost the same to create >>=. 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).

解决方案

Now when you look at it, f(a -> b) can be written as (a -> b)

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 f here, it's part of the type**.

Instead, let's get the facts straight. An 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

Here's another fact: you can define bind ((>>=)) 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)

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 (>>=) for your type if you want to make it a a monad:

instance Monad YourType where
   k >>= f = ...

Also, your join definition uses id which is not in the Monad interface, why is it mathematically legitimate?

First of all, 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).

If we created 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
             --    ^  ^       ^

Join is able to drop one of the 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

The answer is no: none of the tools we're given by 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:

To see the increased power of Monad from a different point of view, let’s see what happens if we try to implement (>>=) 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.

Note that 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.

* 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 (>>=) 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.

这篇关于Monad比Applicative更强大?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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