折叠列表以创建另一个列表



作为一个初学Haskell的程序员,我发现经常做以下事情

let states = foldl processLine [start_state] (lines input)

这些表达式的结果通常是1对1(或一对对1)映射到每一行输入,但是processLine函数需要回顾1或2个状态来计算未来的状态

有更好的方法吗?当我生成一个列表时,使用fold感觉很奇怪。

传递给折叠的状态非常关键,因为这是折叠"知道"的唯一方式。列表中除当前元素以外的任何元素。如果要处理列表中的前两个元素,可以编写如下代码:

data Previous a = NoPrevious | PreviousOne a | PreviousTwo a a 
deriving Show
reverse $ snd $ foldl ((p, acc) x -> case p of { NoPrevious -> (PreviousOne x, []); PreviousOne a -> (PreviousTwo a x, []); PreviousTwo a b -> (PreviousTwo b x, [a,b]:acc) }) (NoPrevious, []) [1,2,3,4,5,6]

其中结果为:

[[1,2],[2,3],[3,4],[4,5]]

如果您希望将其推广到前面任意数量的元素,您可以编写如下内容。(免责声明:根本没有优化。)

foldlPrevN n f init lst = foldlPrevN' n 0 [] f init lst
where
foldlPrevN' _ _ _ _ init [] = init
foldlPrevN' n n' prev f init (x:xs)
| n' < n    = foldlPrevN' n (n' + 1) (prev ++ [x]) f init xs
| otherwise = foldlPrevN' n n (tail prev ++ [x]) f (f init prev x) xs
Prelude> reverse $ foldlPrevN 3 (i p x -> (p, x) : i) [] [1,2,3,4,5,6]
[([1,2,3],4),([2,3,4],5),([3,4,5],6)]
Prelude> reverse $ foldlPrevN 4 (i p x -> (p, x) : i) [] [1,2,3,4,5,6]
[([1,2,3,4],5),([2,3,4,5],6)]
Prelude> reverse $ foldlPrevN 4 (i p x -> (sum p + x) : i) [] [1,2,3,4,5,6]
[15,20]

最新更新