转换Haskell中的2元组列表

Two*_*ist 5 haskell

(背景:尝试学习Haskell,对函数式编程来说很陌生.通常用于Python.)

假设我有一个2元组列表,一个直方图:

let h = [(1,2),(3,5),(4,6),(5,3),(6,7),(7,4),(8,6),(9,1)]
Run Code Online (Sandbox Code Playgroud)

在命令性的术语中,我想将每对中的第二项更改为所有先前第二对的总和.在Python中,以下(公认的复杂)列表理解可以做到:

[(p[0], sum( [p[1] for p in histogram[:i+1]] ))
    for i, p in enumerate(histogram)]
Run Code Online (Sandbox Code Playgroud)

假设histogram是指h如上所述的2元组列表.

这是我到目前为止在Haskell中所拥有的:

zip [fst p | p <- h] (scanl1 (+) [snd k | k <- h])
Run Code Online (Sandbox Code Playgroud)

这有效,但我想知道:

  • 这个阅读列表是一次还是两次?
  • 可以表达得更好吗?(我希望这样.)

如果不清楚,这是上述的预期输出:

[(1,2),(3,7),(4,13),(5,16),(6,23),(7,27),(8,33),(9,34)]
Run Code Online (Sandbox Code Playgroud)

Lee*_*hem 11

你可以使用这个功能

accumulate = scanl1 step
        where step (_,acc) (p1,p2) = (p1,acc+p2)
Run Code Online (Sandbox Code Playgroud)

以下是您的示例数据的结果:

*Main> accumulate h
[(1,2),(3,7),(4,13),(5,16),(6,23),(7,27),(8,33),(9,34)]
Run Code Online (Sandbox Code Playgroud)


Mar*_*189 5

如果你是Haskell的新手,这可能有点太早,但镜头提供了一个很好的简洁方法:

> scanl1Of (traverse . _2) (+) h
[(1,2),(3,7),(4,13),(5,16),(6,23),(7,27),(8,33),(9,34)]
Run Code Online (Sandbox Code Playgroud)

您可以通过切换到_1以下内容轻松累积第一个:

> scanl1Of (traverse . _1) (+) h
[(1,2),(4,5),(8,6),(13,3),(19,7),(26,4),(34,6),(43,1)]
Run Code Online (Sandbox Code Playgroud)

或者将所有值累积为一种嵌套列表:

> scanl1Of (traverse . both) (+) h
[(1,3),(6,11),(15,21),(26,29),(35,42),(49,53),(61,67),(76,77)]
Run Code Online (Sandbox Code Playgroud)