haskell列表理解通过列表monad理解

时间:2018-03-19 09:57:01

标签: haskell

我来自python世界,但尝试尽可能地使用功能,并改变我的命令性思维。

现在我研究haskell并发现

list = [(x,y) | x<-[1,2,3], y<-[4,5,6]]

被翻译为

list' = 
    [1,2,3] >>= \x ->
    [4,5,6] >>= \y ->
    return (x,y)

我尝试逐步理解list monad绑定链的处理:

绑定defind as:

xs >>= f = concat (map f xs)

并且bind是左关联的

所以当我强调,开始时首先使用结果[4,5,6,4执行绑定([1,2,3]&gt;&gt; = \ x - &gt; [4,5,6]) 5,6,4,5,6]

然后接下来绑定 [4,5,6,4,5,6,4,5,6]&gt;&gt; = \ y - &gt; return(x,y)执行

但如果它已经计算好了,它怎么能看到lambda里面的x? x只是根本没有具体值的参数(lambda可以在任何时候使用varios参数调用,我们如何将其置于外部并修复?)。如果它以某种方式可以看到它怎么能知道x呼叫历史是用1,2,3改变的?在我的理解中,第一次绑定计算已经完成,只有结果[4,5,6,4,5,6,4,5,6]可用,接下来是下一个绑定的第一个参数。

所以我无法理解如何阅读这种结构,以及它如何逐步产生正确的结果?

1 个答案:

答案 0 :(得分:6)

这是混淆的常见原因。 lambdas的范围尽可能扩展 ,所以这个:

[1,2,3] >>= \x ->
[4,5,6] >>= \y ->
return (x,y)

等同于:

[1,2,3] >>= (\x ->
  [4,5,6] >>= (\y ->
    return (x,y)))

因此内部lambda \y -> …位于外部lambda \x -> …的范围内,意味着xy都在范围内。然后,您可以为>>= monad实例内联return[]的定义,并逐步完成评估:

concatMap (\x ->
  concatMap (\y ->
    [(x,y)]) [4,5,6]) [1,2,3]

concat
  [ concatMap (\y -> [(1,y)]) [4,5,6]
  , concatMap (\y -> [(2,y)]) [4,5,6]
  , concatMap (\y -> [(3,y)]) [4,5,6]
  ]

concat
  [ concat [[(1,4)], [(1,5)], [(1,6)]]
  , concat [[(2,4)], [(2,5)], [(2,6)]]
  , concat [[(3,4)], [(3,5)], [(3,6)]]
  ]

concat
  [ [(1,4), (1,5), (1,6)]
  , [(2,4), (2,5), (2,6)]
  , [(3,4), (3,5), (3,6)]
  ]

[ (1,4), (1,5), (1,6)
, (2,4), (2,5), (2,6)
, (3,4), (3,5), (3,6)
]

使用ApplicativeMonad)和{{1},使用<$>实例代替fmap实例,这是一种常见且更简洁的表达方式。 (<*>)运算符或ap

liftA2