Monad 比 Applicative 给我们什么优势? [英] What advantage does Monad give us over an Applicative?

查看:24
本文介绍了Monad 比 Applicative 给我们什么优势?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已阅读这篇文章,但没看懂最后一节.

I've read this article, but didn't understand last section.

作者说 Monad 为我们提供了上下文敏感性,但仅使用 Applicative 实例就可以实现相同的结果:

The author says that Monad gives us context sensitivity, but it's possible to achieve the same result using only an Applicative instance:

let maybeAge = (futureYear birthYear -> if futureYear < birthYear
    then yearDiff birthYear futureYear
    else yearDiff futureYear birthYear) <$> (readMay futureYearString) <*> (readMay birthYearString)

没有 do-syntax 肯定更丑,但除此之外,我不明白为什么我们需要 Monad.谁能帮我解决这个问题?

It's uglier for sure without do-syntax, but beside that I don't see why we need Monad. Can anyone clear this up for me?

推荐答案

这里有几个使用 Monad 接口的函数.

Here's a couple of functions that use the Monad interface.

ifM :: Monad m => m Bool -> m a -> m a -> m a
ifM c x y = c >>= z -> if z then x else y

whileM :: Monad m => (a -> m Bool) -> (a -> m a) -> a -> m a
whileM p step x = ifM (p x) (step x >>= whileM p step) (return x)

您不能使用 Applicative 接口实现它们.但是为了开悟,让我们试着看看哪里出了问题.怎么样..

You can't implement them with the Applicative interface. But for the sake of enlightenment, let's try and see where things go wrong. How about..

import Control.Applicative

ifA :: Applicative f => f Bool -> f a -> f a -> f a
ifA c x y = (c' x' y' -> if c' then x' else y') <$> c <*> x <*> y

看起来不错!它有正确的类型,它必须是同一件事!让我们检查一下以确保..

Looks good! It has the right type, it must be the same thing! Let's just check to make sure..

*Main> ifM (Just True) (Just 1) (Just 2)
Just 1
*Main> ifM (Just True) (Just 1) (Nothing)
Just 1
*Main> ifA (Just True) (Just 1) (Just 2)
Just 1
*Main> ifA (Just True) (Just 1) (Nothing)
Nothing

这是您对差异的第一个暗示.您不能仅使用复制 ifMApplicative 接口编写函数.

And there's your first hint at the difference. You can't write a function using just the Applicative interface that replicates ifM.

如果您将其分为将 fa 形式的值视为关于效果"和结果"(这两个都是非常模糊的近似术语,是可用的最佳术语,但是不是很好),你可以在这里提高你的理解.对于 Maybe a 类型的值,效果"是成功或失败,作为计算.结果"是一个 a 类型的值,它可能在计算完成时出现.(这些术语的含义在很大程度上取决于具体类型,因此不要认为这是对 Maybe 以外的任何其他类型的有效描述.)

If you divide this up into thinking about values of the form f a as being about "effects" and "results" (both of which are very fuzzy approximate terms that are the best terms available, but not very good), you can improve your understanding here. In the case of values of type Maybe a, the "effect" is success or failure, as a computation. The "result" is a value of type a that might be present when the computation completes. (The meanings of these terms depends heavily on the concrete type, so don't think this is a valid description of anything other than Maybe as a type.)

鉴于该设置,我们可以更深入地查看差异.Applicative 接口允许结果"控制流是动态的,但它要求效果"控制流是静态的.如果您的表达式涉及 3 个可能失败的计算,则其中任何一个的失败都会导致整个计算失败.Monad 接口更加灵活.它允许效果"控制流依赖于结果"值.ifM 根据第一个参数选择将哪个参数的效果"包含在它自己的效果"中.这就是 ifAifM 之间巨大的根本区别.

Given that setting, we can look at the difference in a bit more depth. The Applicative interface allows the "result" control flow to be dynamic, but it requires the "effect" control flow to be static. If your expression involves 3 computations that can fail, the failure of any one of them causes the failure of the whole computation. The Monad interface is more flexible. It allows the "effect" control flow to depend on the "result" values. ifM chooses which argument's "effects" to include in its own "effects" based on its first argument. This is the huge fundamental difference between ifA and ifM.

whileM 发生了更严重的事情.让我们试着制作 whileA 看看会发生什么.

There's something even more serious going on with whileM. Let's try to make whileA and see what happens.

whileA :: Applicative f => (a -> f Bool) -> (a -> f a) -> a -> f a
whileA p step x = ifA (p x) (whileA p step <*> step x) (pure x)

好吧..发生的是编译错误.(<*>) 那里没有正确的类型.whileA p step 的类型为 a ->f astep x 的类型为 f a.(<*>) 不是将它们组合在一起的正确形状.为了让它工作,函数类型需要是 f (a -> a).

Well.. What happens is a compile error. (<*>) doesn't have the right type there. whileA p step has the type a -> f a and step x has the type f a. (<*>) isn't the right shape to fit them together. For it to work, the function type would need to be f (a -> a).

你可以尝试更多的东西 - 但你最终会发现 whileA 没有任何实现,它的工作方式甚至接近于 whileM 的工作方式.我的意思是,您可以实现该类型,但无法使其同时循环和终止.

You can try lots more things - but you'll eventually find that whileA has no implementation that works anything even close to the way whileM does. I mean, you can implement the type, but there's just no way to make it both loop and terminate.

使其工作需要 join(>>=).(好吧,或者其中之一的许多等价物之一)还有那些你从 Monad 接口中得到的额外东西.

Making it work requires either join or (>>=). (Well, or one of the many equivalents of one of those) And those the extra things you get out of the Monad interface.

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

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