通过列表单子理解haskell列表理解
我来自python世界,但尽量使用functional,并改变我的命令式思维 现在我研究haskell发现通过列表单子理解haskell列表理解,haskell,Haskell,我来自python世界,但尽量使用functional,并改变我的命令式思维 现在我研究haskell发现 list = [(x,y) | x<-[1,2,3], y<-[4,5,6]] 我试图逐步了解列表单子绑定链的处理: 绑定定义为: xs >>= f = concat (map f xs) 而bind是左关联的 正如我所理解的,在开始时,第一个绑定([1,2,3]>=\x->[4,5,6])被执行,结果是[4,5,6,4,5,6,4,5,6] 然后下一个绑定 [
list = [(x,y) | x<-[1,2,3], y<-[4,5,6]]
我试图逐步了解列表单子绑定链的处理:
绑定定义为:
xs >>= f = concat (map f xs)
而bind是左关联的
正如我所理解的,在开始时,第一个绑定([1,2,3]>=\x->[4,5,6])被执行,结果是[4,5,6,4,5,6,4,5,6]
然后下一个绑定
[4,5,6,4,5,6,4,5,6]>>=\y->执行返回(x,y)
但是如果它是allready计算的,它怎么能看到lambda中的x呢??x只是一个根本没有具体值的参数(lambda可以在任何时候用varios参数调用,我们如何在外部使用它并修复??)。如果它能看到它怎么知道x呼叫历史记录被1,2,3改变了?根据我的理解,一旦第一次绑定计算完成,只有结果[4,5,6,4,5,6,4,5,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->…
,意味着x
和y
都在范围内。然后,您可以为[]
monad实例内联>=
和返回
的定义,并逐步完成求值:
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)
]
用
(fmap
)和
(ap
)操作符或liftA2
,用应用程序的实例而不是Monad
实例来表达这一点,这是一种常见且更简洁的方式:
(,) <$> [1,2,3] <*> [4,5,6]
liftA2 (,) [1,2,3] [4,5,6]
(,)[1,2,3][4,5,6]
liftA2(,)[1,2,3][4,5,6]
(,) <$> [1,2,3] <*> [4,5,6]
liftA2 (,) [1,2,3] [4,5,6]