我遇到了一些简短的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; - 有意识地因为订单确实有所不同或完全随意。
祝你好运
京特
答案 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
非交换:
答案 3 :(得分:0)
这个问题实际上有两个层面的答案:
要理解的是:实例化Monad
的任何类型都必须遵守monad laws,这要求某些表达式是等价的(例如(a >> b) >> c == a >> (b >> c)
)。但是monad法律并没有禁止个别monad拥有额外的等价物。
monad法律本身并不要求你的两个功能是等同的;因此:
另一方面,几个monad确实使你的功能相同;例如,Maybe
和Reader
可以。服从等价的monad被称为可交换的 monad-one,其效果的顺序无关紧要。