使用foldr1:
intercalate' :: [a] -> [[a]] -> [a]
intercalate' _ [] = []
intercalate' x xs = foldr1 (\a acc -> a ++ x ++ acc) xs
这将在每个元素之间插入来自 right 的值与 x。 (尽管它这样做了lazily。– 直到需要时才评估整个折叠。)
foldr1 和foldr 的相似之处在于它们从右侧折叠。不同之处在于前者不需要我们提供最终期限,而后者确实需要提供最终期限。这需要我们对空列表进行模式匹配,否则会抛出异常。
确实,foldl1 也可以完成插层。但是,强烈建议不要这样做,因为左折叠会急切地消耗输入。
intercalate' :: [a] -> [[a]] -> [a]
intercalate' _ [] = []
intercalate' x xs = foldl1 (\acc a -> acc ++ x ++ a) xs
为了进一步强调对正确折叠的偏好,请考虑以下组合:
take 10 . intercalate' [0] $ repeat [1..3]
看起来无害。但是使用foldl1 会急切地消耗无限列表,而不是停止进程。
但是,使用foldr1 将延迟评估并给出[1,2,3,0,1,2,3,0,1,2] 的正确结果。 (intercalate' 将在 take 10 询问前导词并评估折叠之前临时评估 [1..3] ++ [0] ++ (foldr (...) [0] [elem1 ... elemN])。)
向Will致敬。
实用阅读:
foldl versus foldr behaviour with infinite lists