用 Haskell 合并两个嵌套列表的元素

Merging the elements of two nested lists with Haskell

我想在一个列表中附加列表,在第二个列表中附加列表。

使用 concat 创建所有元素的一个列表,而 zip 似乎将两个嵌套列表组合成一个嵌套列表而不组合子列表。

let x = [["one", "two"],["five", "six"], ["nine", "ten"]] 

let y = [["three", "four"],["seven", "eight"], ["eleven", "twelve"]]

应该变成

[["one", "two", "three", "four"], ["five", "six", "seven", "eight"], ["nine", "ten", "eleven", "twelve"]]

如何实现上述结果?我的直觉是使用 map 虽然我一直没有成功。

在某些语言中,如 Scheme map 可以接受任意数量的列表,但在 Haskell 中,二进制 map 有自己的名称,zipWith:

zipWith (++) x y

会做你想做的。

如何到达那里,在 REPL 玩:

> zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
-- BTW these are not lists, but tuples

> zipWith (,) x y                    -- same thing as zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]

> zipWith (\a b -> (a,b)) x y        -- same thing as the above
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]

> zipWith (\a b -> [a,b]) x y        -- not the same thing as the above
[[["one","two"],["three","four"]],[["five","six"],["seven","eight"]],[["nine","ten"],["eleven","twelve"]]]

> zipWith (\a b -> concat [a,b]) x y    -- success!
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]

> zipWith (\a b -> a ++ b) x y       -- equivalent to the above
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]

> zipWith (++) x y                   -- finally, simplified.
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]

但是您可以也可以根据需要使用map来处理zip的输出:

> zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]

> map id $ zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]

> map (\(a,b) -> a ++ b) $ zip x y   -- the same as zipWith (++)
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]

实现此目的的另一种方法是使用 transpose,它本身就是一种 zip

map concat $ transpose [x,y]

这使用与我们在上面看到的相同的 concat 两个列表,现在可以处理任意数量的子列表,每个子列表都来自原始列表(这里仍然是两个):

> transpose [x,y]
[[["one","two"],["three","four"]],[["five","six"],["seven","eight"]],[["nine","ten"],["eleven","twelve"]]]

因此它可以毫不费力地扩展到处理任意数量的列表:

map concat $ transpose [x,y,z]

等等