1

使用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)]

上面的单子表达式似乎不对应于单子结合律的任何一边:

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

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

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

因为return (x,y)对周围的函数和包含它的函数都关闭,所以似乎存在于结合律左侧的中间单子(m >>= f)在此示例中不存在。

4

3 回答 3

7

我认为您将一元定律与一元表达式的结构混淆了。monadic 结合律规定表达式(m >>= f) >>= g必须等价于被视为 monadm >>= (\x -> f x >>= g)的数据类型的表达式。m

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

例如m >>= f是一个完全有效的单子表达式,即使它不是(m >>= f) >>= g. 但是它仍然遵守一元结合律,因为m可以扩展为m >>= return(从一元右身份律m >>= return ≡ m)。因此:

m >>= f

-- is equivalent to

(m >>= return) >>= f

-- is of the form

(m >>= f) >>= g

在您的示例中是where ism >>= (\x -> ys >>= (\y -> return (x, y)))的形式。m >>= ff\x -> ys >>= (\y -> return (x, y))

虽然\x -> ys >>= (\y -> return (x, y))不是形式\x -> f x >>= g(从一元结合律的右侧),但这并不意味着它违反了一元律。

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

(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))))

希望能澄清事情。

于 2014-03-02T07:35:39.370 回答
3

x实际上,由于原始表达式中的范围,不可能直接应用结合律:

import Control.Monad (liftM)

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

x但是,如果我们将其包含在第一个单子计算的结果中,我们可以缩小范围。我们将使用和 return而不是return [Int]in ,其中每对中的第一个数字始终是,第二个是 of 中的一个。(注意 for 列表与 相同。)第二个函数将从其输入中读取 的值:x -> ys\x -> liftM ((,) x) ys[(Int,Int)]xysliftMmapx

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

(monadic 函数\(x', y) -> return (x', y)现在可以简化为return,然后>>= return完全删除,但为了论证,我们将其保留在那里。)

现在每个一元函数都是自包含的,我们可以应用结合律:

test2 = let m = [1,2]
            ys = [4, 5, 6]
        in (m >>= \x -> liftM ((,) x) ys) >>= (\(x, y) -> return (x, y))
于 2014-03-02T07:06:24.270 回答
1

一元定律仅适用于一个参数的函数。表达方式

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

真的相当于:

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

(如果我们要避免捕获x

所以你不能应用同样的定律——我们有fmapasf和 nog来自结合律。

上面当然是一样的:

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

或者

xs >>= \x -> fmap (\y -> (x,y)) ys
于 2014-03-04T10:09:07.667 回答