Monad给我们的应用程序有什么优势? [英] What advantage does Monad give us over an Applicative?

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

问题描述

我读过这篇文章

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 code> interface。

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

暗示差异。您不能使用复制 ifM Applicative 接口编写函数。

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 根据第一个参数选择哪个参数的效果包含在其自身的效果中。这是 ifA ifM 之间巨大的根本区别。

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)

那么会发生什么是编译错误。 (< *>)在那里没有正确的类型。 while a p step 的类型为 a - > f a step 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.

使它工作要求要么加入(>> =)。 (嗯,或者其中一个等价物之一)以及你从 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给我们的应用程序有什么优势?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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