这些monadic表达式是否相同

时间:2014-10-01 13:44:46

标签: haskell monads

我遇到了一些简短的monadic代码,我有一个与示例的实际主题无关的问题

ap :: (Monad m) => m (a -> b) -> m a -> m b
ap mf mx = do
        f <- mf
        x <- mx
        return (f x)

保持纯粹的象征性而不知道所有上下文或代码“做”,上面等同于

ap :: (Monad m) => m (a -> b) -> m a -> m b
ap mf mx = do
        x <- mx
        f <- mf
        return (f x)

当我第一次看到示例代码时,我想知道是否有一个原因是这个代码的作者选择了f&lt; -mf,x&lt; -mx over x&lt; -mx,f&lt; - 有意识地因为订单确实有所不同或完全随意。

祝你好运

京特

4 个答案:

答案 0 :(得分:4)

一个简单的例子,它们不相同(因为它们有不同的副作用):

mf :: IO (Int -> Int)
mf = do
    putStr "Hello, "
    return (+1)

mx :: IO Int
mx = do
    putStr "world"
    return 1

ap1 = Control.Monad.ap
ap2 mf mx = do
    x <- mx
    f <- mf
    return (f x)

并测试出来

> void $ ap1 mf mx
Hello, world
> void $ ap2 mf mx
worldHello, 

即使计算的实际结果在两种情况下相同,即2,这些结果显然是完全不同的结果。

答案 1 :(得分:4)

不,他们不等同。 Desugared,他们是

mf >>= (\f -> mx >>= (\x -> return (f x)))
mx >>= (\x -> mf >>= (\f -> return (f x)))

因此绑定操作首先应用于mf,第一个定义应用mx秒,而第二个定义应用另一种方式。绑定不是可交换的,或者至少它不需要(monad法律不要求它)。不涉及IO的反例是mf = [(+1), (+2)]mx = [1, 5]

答案 2 :(得分:0)

正如其他人所指出的,IO是一个简单的反例。列表monad也不是可交换的。

Prelude> do f<-[succ,pred] ; x<-[10,20] ; return (f x)
[11,21,9,19]
Prelude> do x<-[10,20] ; f<-[succ,pred] ; return (f x)
[11,9,21,19]

让我们建立一个可交换的monad列表。

<强>可交换

  • 身份
  • 读者/ (->) a
  • 也许
  • Cont(我猜?)
  • [](如果您无视订单)
  • 随机(至少在道德上)
  • UniqueSupply(至少在道德上)

非交换

  • 作家
  • 国家
  • IO / ST
  • STM
  • [](如果订单很重要)
  • 要么
  • 随机(正式)
  • UniqueSupply(正式)

答案 3 :(得分:0)

这个问题实际上有两个层面的答案:

  1. 从monad法律的角度来看,这两个表达式是否等同于
  2. 从特定monad 的角度来看,这两个表达式是否等同于
  3. 要理解的是:实例化Monad的任何类型都必须遵守monad laws,这要求某些表达式是等价的(例如(a >> b) >> c == a >> (b >> c))。但是monad法律并没有禁止个别monad拥有额外的等价物。

    monad法律本身并不要求你的两个功能是等同的;因此:

    • 有一些特定的monad,你的两个函数是等价的,而另一些则不是。
    • 如果你正在编写适用于任意monad的代码,你可能不会认为是等价的。

    另一方面,几个monad确实使你的功能相同;例如,MaybeReader可以。服从等价的monad被称为可交换的 monad-one,其效果的顺序无关紧要。