foldr 和 zipWith(:) 如何协同工作?
How do foldr and zipWith (:) work together?
我是 Haskell 的新手,我遇到了以下令我困惑的代码:
foldr (zipWith (:)) (repeat []) [[1,2,3],[4,5,6],[7,8,9,10]]
它产生了以下结果,在试用它之后,我不完全确定为什么:
[[1,4,7],[2,5,8],[3,6,9]]
我的印象是 (:)
将项目添加到列表中,并且 (repeat [])
会产生无穷无尽的空列表 []
,并且 foldr
接受一个函数、一个项目和一个列表,并通过将函数连同结果连续应用于列表中的每个项目来压缩列表。
也就是说,我直观地理解了下面的代码是如何产生结果10的:
foldr (+) 1 [2,3,4]
但是,我完全不确定为什么 foldr (zipWith (:)) (repeat [])
需要一个列表列表并生成另一个列表列表,其中的项目按其原始内部索引分组。
任何解释都会很有启发性。
所以使用 foldr
从右边折叠列表的直觉(这不是递归定义)你在简单的情况下得到以下内容:
foldr (+) 1 [2,3,4]
foldr (+) (4 + 1) [2,3]
foldr (+) (3 + 4 + 1) [2]
foldr (+) (2 + 3 + 4 + 1) []
(2 + 3 + 4 + 1)
10
让我们在您的示例中做同样的事情并考虑初始元素 repeat [] == [[],[],[],[], …]
foldr (zipWith (:)) ([[],[],[],[], ...]) [[1,2,3],[4,5,6],[7,8,9,10]]
foldr (zipWith (:)) (zipWith (:) [7,8,9,10] [[],[],[],[], ...]) [[1,2,3],[4,5,6]]
等一下。让我们发展 zipWith (:) [7,8,9,10] [[],[],[],[], ...]
zipWith (:) [7,8,9,10] [[],[],[],[], ...] -- apply the funciton (:) pairwise
[7:[], 8:[], 9:[], 10:[]] -- we get rid of the infinite list at this point.
[[7],[8],[9],[10]]
从这里我们可以轻松地了解其余代码
foldr (zipWith (:)) ([[],[],[],[], ...]) [[1,2,3],[4,5,6],[7,8,9,10]]
foldr (zipWith (:)) (zipWith (:) [7,8,9,10] [[],[],[],[], ...]) [[1,2,3],[4,5,6]]
foldr (zipWith (:)) ([[7],[8],[9],[10]]) [[1,2,3],[4,5,6]]
foldr (zipWith (:)) (zipWith (:) [4,5,6] [[7],[8],[9],[10]]) [[1,2,3]]
foldr (zipWith (:)) (zipWith (:) [1,2,3] [[4:7],[5:8],[6:9]) []
zipWith (:) [1,2,3] [[4:7],[5:8],[6:9]
[[1,4,7],[2,5,8],[3,6,9]]
请注意,这不是 foldr
的正确定义,我们正在立即而不是延迟地评估结果(如 haskell 那样),但这只是为了便于理解。
这个很简单。 foldr
定义为
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
因此,
foldr f z [a,b,c,...,n] = f a (f b (f c (...(f n z)...)))
或者,在这里,
foldr (zipWith (:)) (repeat []) [[1,2,3],[4,5,6],[7,8,9,10]]
=
zipWith (:) [1,2,3]
( foldr (zipWith (:)) (repeat []) [[4,5,6],[7,8,9,10]] )
=
...
=
zipWith (:) [1,2,3]
( zipWith (:) [4,5,6]
( zipWith (:) [7,8,9,10]
( foldr (zipWith (:)) (repeat []) [] )))
=
zipWith (:) [1,2,3]
( zipWith (:) [4,5,6]
( zipWith (:) [7,8,9,10]
( repeat [] )))
=
zipWith (:) [1,2,3]
( zipWith (:) [4,5,6]
( zipWith (:) [ 7, 8, 9,10]
[[],[],[],[],[],[],....] ))
=
zipWith (:) [1,2,3]
( zipWith (:) [ 4, 5, 6 ]
[[7],[8],[9],[10]] )
=
zipWith (:) [ 1 , 2 , 3 ]
[[4,7],[5,8],[6,9]]
就是这样。
(菜单上的下一个,traverse ZipList [[1,2,3],[4,5,6],[7,8,9,10]]
... :) 或者稍后。)
至于另一个例子,就是
foldr (+) 1 [2,3,4]
= 2 + foldr (+) 1 [3,4]
= 2 + (3 + foldr (+) 1 [4])
= 2 + (3 + (4 + foldr (+) 1 []))
= 2 + (3 + (4 + 1))
= 2 + (3 + 5)
= 2 + 8
= 10
因为 +
在其两个参数中都是 strict。
zipWith
在两个参数中都不严格,(:)
也不严格,所以第一个序列应该仅作为说明。实际的强制将以自上而下的顺序发生,而不是自下而上。例如,
> map (take 1) . take 1 $ zipWith (:) (1 : undefined) (repeat undefined)
[[1]]
完全符合
map (take 1) . take 1 $ zipWith (:) (1 : undefined) (repeat undefined)
=
map (take 1) . take 1 $ zipWith (:) (1 : undefined) (undefined : repeat undefined)
=
map (take 1) . take 1 $ (1 : undefined) : zipWith (:) undefined (repeat undefined)
=
map (take 1) $ (1 : undefined) : take 0 (zipWith (:) undefined (repeat undefined))
=
map (take 1) $ (1 : undefined) : []
=
map (take 1) [(1 : undefined)]
=
[take 1 (1 : undefined)]
=
[1 : take 0 undefined]
=
[1 : []]
=
[[1]]
我是 Haskell 的新手,我遇到了以下令我困惑的代码:
foldr (zipWith (:)) (repeat []) [[1,2,3],[4,5,6],[7,8,9,10]]
它产生了以下结果,在试用它之后,我不完全确定为什么:
[[1,4,7],[2,5,8],[3,6,9]]
我的印象是 (:)
将项目添加到列表中,并且 (repeat [])
会产生无穷无尽的空列表 []
,并且 foldr
接受一个函数、一个项目和一个列表,并通过将函数连同结果连续应用于列表中的每个项目来压缩列表。
也就是说,我直观地理解了下面的代码是如何产生结果10的:
foldr (+) 1 [2,3,4]
但是,我完全不确定为什么 foldr (zipWith (:)) (repeat [])
需要一个列表列表并生成另一个列表列表,其中的项目按其原始内部索引分组。
任何解释都会很有启发性。
所以使用 foldr
从右边折叠列表的直觉(这不是递归定义)你在简单的情况下得到以下内容:
foldr (+) 1 [2,3,4]
foldr (+) (4 + 1) [2,3]
foldr (+) (3 + 4 + 1) [2]
foldr (+) (2 + 3 + 4 + 1) []
(2 + 3 + 4 + 1)
10
让我们在您的示例中做同样的事情并考虑初始元素 repeat [] == [[],[],[],[], …]
foldr (zipWith (:)) ([[],[],[],[], ...]) [[1,2,3],[4,5,6],[7,8,9,10]]
foldr (zipWith (:)) (zipWith (:) [7,8,9,10] [[],[],[],[], ...]) [[1,2,3],[4,5,6]]
等一下。让我们发展 zipWith (:) [7,8,9,10] [[],[],[],[], ...]
zipWith (:) [7,8,9,10] [[],[],[],[], ...] -- apply the funciton (:) pairwise
[7:[], 8:[], 9:[], 10:[]] -- we get rid of the infinite list at this point.
[[7],[8],[9],[10]]
从这里我们可以轻松地了解其余代码
foldr (zipWith (:)) ([[],[],[],[], ...]) [[1,2,3],[4,5,6],[7,8,9,10]]
foldr (zipWith (:)) (zipWith (:) [7,8,9,10] [[],[],[],[], ...]) [[1,2,3],[4,5,6]]
foldr (zipWith (:)) ([[7],[8],[9],[10]]) [[1,2,3],[4,5,6]]
foldr (zipWith (:)) (zipWith (:) [4,5,6] [[7],[8],[9],[10]]) [[1,2,3]]
foldr (zipWith (:)) (zipWith (:) [1,2,3] [[4:7],[5:8],[6:9]) []
zipWith (:) [1,2,3] [[4:7],[5:8],[6:9]
[[1,4,7],[2,5,8],[3,6,9]]
请注意,这不是 foldr
的正确定义,我们正在立即而不是延迟地评估结果(如 haskell 那样),但这只是为了便于理解。
这个很简单。 foldr
定义为
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
因此,
foldr f z [a,b,c,...,n] = f a (f b (f c (...(f n z)...)))
或者,在这里,
foldr (zipWith (:)) (repeat []) [[1,2,3],[4,5,6],[7,8,9,10]]
=
zipWith (:) [1,2,3]
( foldr (zipWith (:)) (repeat []) [[4,5,6],[7,8,9,10]] )
=
...
=
zipWith (:) [1,2,3]
( zipWith (:) [4,5,6]
( zipWith (:) [7,8,9,10]
( foldr (zipWith (:)) (repeat []) [] )))
=
zipWith (:) [1,2,3]
( zipWith (:) [4,5,6]
( zipWith (:) [7,8,9,10]
( repeat [] )))
=
zipWith (:) [1,2,3]
( zipWith (:) [4,5,6]
( zipWith (:) [ 7, 8, 9,10]
[[],[],[],[],[],[],....] ))
=
zipWith (:) [1,2,3]
( zipWith (:) [ 4, 5, 6 ]
[[7],[8],[9],[10]] )
=
zipWith (:) [ 1 , 2 , 3 ]
[[4,7],[5,8],[6,9]]
就是这样。
(菜单上的下一个,traverse ZipList [[1,2,3],[4,5,6],[7,8,9,10]]
... :) 或者稍后。)
至于另一个例子,就是
foldr (+) 1 [2,3,4]
= 2 + foldr (+) 1 [3,4]
= 2 + (3 + foldr (+) 1 [4])
= 2 + (3 + (4 + foldr (+) 1 []))
= 2 + (3 + (4 + 1))
= 2 + (3 + 5)
= 2 + 8
= 10
因为 +
在其两个参数中都是 strict。
zipWith
在两个参数中都不严格,(:)
也不严格,所以第一个序列应该仅作为说明。实际的强制将以自上而下的顺序发生,而不是自下而上。例如,
> map (take 1) . take 1 $ zipWith (:) (1 : undefined) (repeat undefined)
[[1]]
完全符合
map (take 1) . take 1 $ zipWith (:) (1 : undefined) (repeat undefined)
=
map (take 1) . take 1 $ zipWith (:) (1 : undefined) (undefined : repeat undefined)
=
map (take 1) . take 1 $ (1 : undefined) : zipWith (:) undefined (repeat undefined)
=
map (take 1) $ (1 : undefined) : take 0 (zipWith (:) undefined (repeat undefined))
=
map (take 1) $ (1 : undefined) : []
=
map (take 1) [(1 : undefined)]
=
[take 1 (1 : undefined)]
=
[1 : take 0 undefined]
=
[1 : []]
=
[[1]]