2014-03-02 135 views
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))) 

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

+0

我不太看的关联性法律的右手侧的功能。 'ys'不消耗绑定的'x',即你的函数不是一元正规形式。 – thumphries

+0

@shelf我认为它归结为这样一个事实:'\ x - > x'是一个函数,但'\ x - >(x,y)'不是。例如, '[1,2] >> =(\ x - > [x,x + 1] >> =(\ y - > [y + 20,y-20]))''given'[21 ,[-19,22,-18,22,-18,23,-17]'和(尊重联想律) '[1,2] >> =(\ x - > [x,x + 1]) >> =(\ y - > [y + 20,y-20])'给出了'[21,-19,22,-18,22,-18,23,-17]'然而,尽管 '[1 ,2] >> =(\ x - > [x,x + 1] >> =(\ y - > [x + y + 20,y-20]))''给出'[22,-19,23, -18,24,-17]',这 '[1,2] >> =(\ x - > [x,x + 1])>> =(\ y - > [x + y + 20,y-20])'会产生错误 –

回答

3

事实上,这是不可能的,直接运用联想法,因为x在原来的表达范围:但是

import Control.Monad (liftM) 

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

,我们可以减少x范围,如果我们包括它到结果第一个单子计算。我们将使用\x -> liftM ((,) x) ys并返回[(Int,Int)],而不是在x -> ys中返回[Int],其中每对中的第一个数字始终为x,第二个数字为ys之一。 (请注意,列出liftM相同map。),第二个函数将其输入读取的x值:

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)现在可以进行简化只是为了return,随后>>= return完全去除,但让我们保持那里的参数的缘故)

现在每个单子的功能是独立的,我们可以应用关联法:

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

为什么当每个m >> = f'形式的单子表达式都可以简单地扩展为'(m >> = return)时,你会使用'liftM' >> = f'把它提升到联想一元定律形式 - '(m >> = f)>> = g'? –

+0

考虑'liftM'扩展到什么是很重要的。 –

7

我认为你混淆了单子表达式结构的一元法则。单子关联性法则规定(m >>= f) >>= g的表达式必须等于m的数据类型的表达式m >>= (\x -> f x >>= g)被视为单子。

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

例如m >>= f是一个完全有效的monadic表达式,即使它不是(m >>= f) >>= g的形式。然而它仍然服从一元结合律,因为m可以扩展到m >>= return(来自单子正确的身份法律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的形式(来自单子结合律的右手边),但这并不意味着它打破了一元法则。

表达m >>= (\x -> ys >>= (\y -> return (x, y)))可以通过用于mm >>= return被扩展到一元关联形式:

(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

单子法只适用于一个参数的函数。表达

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

是真的等同于:

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

(如果我们要避免捕捉x

所以你不能适用同样的法律 - 我们有fmapf和no g来自关联性法则。

以上当然是一样的:

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

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