Haskell:高效累加器

Posted

技术标签:

【中文标题】Haskell:高效累加器【英文标题】:Haskell: Efficient accumulator 【发布时间】:2016-02-02 00:12:14 【问题描述】:

当您的结果与列表的类型不同时,使用每个映射的结果来映射列表的最佳方式是什么。

例如

f :: Int -> Int -> String -> String

l = [1,2,3,4]

我想要一些沿着列表 l 走的东西:

f 1 2 [] = result1 => f 2 3 result1 = result2 => f 3 4 result3 ==> return result3.

我可以让它与一个累加器一起工作,但它看起来相当麻烦。有没有标准的方法来做到这一点......或者这是 Monads 的东西?

谢谢!

注意上面的功能只是为了说明。

【问题讨论】:

一般来说你可以使用滑动窗口 【参考方案1】:

这只是输入列表中对的一个折叠:

f :: Int -> Int -> String -> String
f = undefined

accum :: [Int] -> String
accum xs = foldl (flip . uncurry $ f) "" $ zip xs (drop 1 xs)

您可能想使用Data.List.foldl' 而不是foldl,但这是一个仅适用于 Prelude 的答案。

【讨论】:

没有理由害怕foldl'【参考方案2】:

似乎是fold 的工作:

func f l = foldl (\s (x, y) -> f x y s) "" (zip l (tail l))

-- just some placeholder function
f :: Int -> Int -> String -> String
f x y s = s ++ " " ++ show(x) ++ " " ++ show(y)

l = [1,2,3,4]

main = print $ func f l

打印:

" 1 2 2 3 3 4"

(如果你能改变f的签名,你就可以摆脱重新排列参数的丑陋的lambda)

【讨论】:

【参考方案3】:

当然,您可以传递折叠累加器中的前一个元素,而不是压缩。例如:

l = [1,2,3,4]
f x y = (x,y)
g b@(accum,prev) a = (accum ++ [f prev a],a)

main = print (foldl g ([],head l) (tail l))

输出:

([(1,2),(2,3),(3,4)],4)

【讨论】:

以上是关于Haskell:高效累加器的主要内容,如果未能解决你的问题,请参考以下文章

Haskell中的懒惰和尾递归,为啥会崩溃?

惯用高效的 Haskell 追加?

在 Haskell 中实现一个高效的滑动窗口算法

Haskell 中的内存高效字符串

Haskell 中字节流的高效流式传输和操作

Haskell:当不需要日志时,让 Writer 和普通代码一样高效