文件夹和zipWith(:)如何一起工作?

And*_*rdo 5 haskell fold zipwith

我是Haskell的新手,并且遇到了以下使我感到困惑的代码:

foldr (zipWith (:)) (repeat []) [[1,2,3],[4,5,6],[7,8,9,10]]
Run Code Online (Sandbox Code Playgroud)

它产生以下结果,在反复试验之后,我不完全确定为什么:

[[1,4,7],[2,5,8],[3,6,9]]
Run Code Online (Sandbox Code Playgroud)

我的印象是,(:)将项目添加到列表中,并(repeat [])产生无数的空列表[],并foldr接受一个函数,一个项目和一个列表,并通过将函数连续应用于列表中的每个项目来压缩列表。列出结果。

也就是说,我直观地理解以下代码如何产生结果10:

foldr (+) 1 [2,3,4]
Run Code Online (Sandbox Code Playgroud)

但是,我完全不确定为什么要使用foldr (zipWith (:)) (repeat [])一个列表列表并生成另一个列表列表,这些列表中的项按其原始内部索引分组。

任何解释都是有启发性的。

Wil*_*ess 5

这很简单。foldr被定义为

foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
Run Code Online (Sandbox Code Playgroud)

从而,

foldr f z [a,b,c,...,n] = f a (f b (f c (...(f n z)...)))
Run Code Online (Sandbox Code Playgroud)

或者在这里

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]] 
Run Code Online (Sandbox Code Playgroud)

就是这样。

(菜单上的下一步,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
Run Code Online (Sandbox Code Playgroud)

因为+严格在它的两个参数。

zipWith在两个参数中都不严格,也不是(:),因此第一个序列应仅用作说明。实际强制将以自上而下的顺序而不是自下而上的顺序发生。例如,

> map (take 1) . take 1 $ zipWith (:) (1 : undefined) (repeat undefined)
[[1]]
Run Code Online (Sandbox Code Playgroud)

完全符合

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]]
Run Code Online (Sandbox Code Playgroud)