我正在尝试制作一个相对简单的函数,它几乎是 concat 但有点扭曲。它应该将每个列表的最后一个和第一个元素二进制或组合在一起,并在此过程中将它们组合起来。我正在努力学习编写可以利用 Data.List.Stream 中的流融合功能的代码
我检查了 base 中的 concat 是否完成了所需的操作并懒惰地构建了列表,但是,我创建的这个版本没有。在基础中, concat 指定如下:
concat :: [[a]] -> [a]
concat = foldr (++) []
(++) :: [a] -> [a] -> [a]
(++) [] ys = ys
(++) (x:xs) ys = x : xs ++ ys
这是我的代码:
bconcat :: [[Word8]] -> [Word8]
bconcat = foldr1 bappend
bappend :: [Word8] -> [Word8] -> [Word8]
bappend as bs = init as ++ (last as .|. head bs) : tail bs
我的问题是,我该如何编写这个列表以便懒惰地构建列表?我什至尝试通过模仿 base 中的 (++) 定义来编写 bappend,但这并没有什么不同。
目前,我使用以下代码,它按我想要的方式工作,但性能落后于 concat。此外,它使用了我想避免的显式递归。
bconcat :: [[Word8]] -> [Word8]
bconcat (a:b:xs) = init a ++ bconcat ((bappend (last a) b):xs)
bconcat (a:[]) = a
bconcat [] = []
bappend :: Word8 -> [Word8] -> [Word8]
bappend !a bs = (a .|. head bs) : tail bs
所以,我的问题是,我该如何编写这段代码,以便它懒惰地构建列表并且没有显式递归?
感谢您的时间。
编辑:
目前,我的主要兴趣是使用标准组合器制作干净、简洁和不稳定的代码。我仍然是功能性思维的初学者,并且希望看到一种合理有效的方式将它们在这里使用。
最佳答案
你的定义对我来说看起来很严格。例如,尝试评估
length $ bconcat [[1,2,3],[4,undefined,6]]
但是您可能正在为 .| 建立 thunk。表达。也许你想强制它。
如果它们不能很好地自动融合,您总是可以自己融合事物:
bconcat [] = error "bconcat: empty outer list"
bconcat (xs:xss) = loop xss xs
where loop [] ys = ys
loop ((x:xs):xss) [y] = let z = x .|. y in seq z $ z : loop xss xs
loop ([]:_) _ = error "bconcat: empty inner list"
loop xss (y:ys) = y : loop xss ys
关于optimization - 在 Haskell 中, concat 懒惰地构建一个列表,但我自己的版本有一个扭曲,没有,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5362292/