monad相关性定律中的未绑定变量

时间:2014-03-02 06:21:26

标签: haskell closures monads associativity

使用ghci我已计算:

Prelude> let m = [1,2]
Prelude> let ys = [4, 5, 6]
Prelude> m >>= (\x -> ys >>= (\y -> return (x, y)))
[(1,4),(1,5),(1,6),(2,4),(2,5),(2,6)]

上面的monadic表达似乎不符合monad关联法的任何一方:

(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)

我想知道monad关联性如何应用于表达式:

m >>= (\x -> ys >>= (\y -> return (x, y))) 

因为return (x,y)关闭了周围的函数和包含它的那个函数,所以在这个例子中,似乎不存在关联性法则(m >>= f)左侧存在的中间monad。

3 个答案:

答案 0 :(得分:7)

我认为你对monadic表达的结构混淆了monadic定律。 monadic associativity法规定,(m >>= f) >>= g表达式必须等同于m >>= (\x -> f x >>= g)的表达式m才能被视为monad。

这并不意味着每个monadic表达式必须是(m >>= f) >>= g形式。

例如,m >>= f是完全有效的monadic表达式,即使它不是(m >>= f) >>= g形式。然而,它仍然遵守monadic相关性法则,因为m可以扩展到m >>= return(来自monadic权利身份法m >>= return ≡ m)。因此:

m >>= f

-- is equivalent to

(m >>= return) >>= f

-- is of the form

(m >>= f) >>= g

在您的示例中,m >>= (\x -> ys >>= (\y -> return (x, y)))的格式为m >>= f,其中f\x -> ys >>= (\y -> return (x, y))

虽然\x -> ys >>= (\y -> return (x, y))不是\x -> f x >>= g形式(来自monadic associativity law的右侧),但并不意味着它违反了monadic定律。

通过将m >>= (\x -> ys >>= (\y -> return (x, y)))替换为m >>= return,表达式m可以扩展为monadic关联形式:

(m >>= return) >>= (\x -> ys >>= (\y -> return (x, y)))

-- is of the form

(m >>= f) >>= g

-- and can be written as

m >>= (\x -> return x >> (\x -> ys >>= (\y -> return (x, y))))

希望澄清事情。

答案 1 :(得分:3)

实际上,由于原始表达式中x的范围,因此不可能直接应用关联法则:

import Control.Monad (liftM)

test = let m = [1,2]
           ys = [4, 5, 6]
       in m >>= (\x -> ys >>= (\y -> return (x, y)))

但是,如果我们将它包含在第一个monadic计算的结果中,我们可以缩小x的范围。我们不会在[Int]中返回x -> ys,而是使用\x -> liftM ((,) x) ys并返回[(Int,Int)],其中每对中的第一个数字始终为x,第二个数字为ys liftM之一。 (请注意,对于列表mapx相同。)第二个函数将从其输入中读取test1 = let m = [1,2] ys = [4, 5, 6] in m >>= (\x -> liftM ((,) x) ys >>= (\(x', y) -> return (x', y))) 的值:

\(x', y) -> return (x', y)

(monadic函数return现在可以简化为>>= return,随后test2 = let m = [1,2] ys = [4, 5, 6] in (m >>= \x -> liftM ((,) x) ys) >>= (\(x, y) -> return (x, y)) 被完全删除,但是为了参数,让它保留在那里。)

现在每个monadic函数都是自包含的,我们可以应用关联性法则:

{{1}}

答案 2 :(得分:1)

monadic法仅适用于一个参数的功能。表达式

xs >>= (\x -> ys >>= (\y -> (x, y)))

实际上相当于:

xs >>= \x -> fmap ($ x) $ ys >>= \y -> return (\x -> (x,y))

(如果我们要避免捕获x

因此,您无法应用相同的法律 - 我们在关联法律中fmapfg没有xs >>= \x -> fmap ($ x) $ fmap (\y x -> (x,y)) ys

以上内容当然与:

相同
xs >>= \x -> fmap (\y -> (x,y)) ys

{{1}}