(背景:尝试学习Haskell,对函数式编程很新。通常用于Python。)
假设我有一个2元组的列表,直方图:
let h = [(1,2),(3,5),(4,6),(5,3),(6,7),(7,4),(8,6),(9,1)]
在命令性的术语中,我想将每对中的第二项更改为所有先前第二对的总和。在Python中,以下(公认的复杂)列表理解可以做到:
[(p[0], sum( [p[1] for p in histogram[:i+1]] ))
for i, p in enumerate(histogram)]
假设histogram
引用了上面h
之类的2元组列表。
这是我到目前为止在Haskell中所拥有的:
zip [fst p | p <- h] (scanl1 (+) [snd k | k <- h])
这有效,但我想知道:
如果不清楚,这是上述的预期输出:
[(1,2),(3,7),(4,13),(5,16),(6,23),(7,27),(8,33),(9,34)]
答案 0 :(得分:11)
您可以使用此功能
accumulate = scanl1 step
where step (_,acc) (p1,p2) = (p1,acc+p2)
以下是您的示例数据的结果:
*Main> accumulate h
[(1,2),(3,7),(4,13),(5,16),(6,23),(7,27),(8,33),(9,34)]
答案 1 :(得分:5)
如果你是Haskell的新手,这可能有点太早了,但lens提供了一个很简洁的方法:
> scanl1Of (traverse . _2) (+) h
[(1,2),(3,7),(4,13),(5,16),(6,23),(7,27),(8,33),(9,34)]
您可以通过切换到_1
:
> scanl1Of (traverse . _1) (+) h
[(1,2),(4,5),(8,6),(13,3),(19,7),(26,4),(34,6),(43,1)]
或者将所有值累积为一种嵌套列表:
> scanl1Of (traverse . both) (+) h
[(1,3),(6,11),(15,21),(26,29),(35,42),(49,53),(61,67),(76,77)]
答案 2 :(得分:4)
嗯,...... (,)
是Data.Bifunctor
和Data.Biapplicative
scanl1 (biliftA2 (flip const) (+))
是你想要的。
Functor
是f
类型,任何a
都可以将任何函数a->b
应用于f a
以获取f b
。例如,(a,)
是Functor
:有一种方法可以应用任何函数b->c
将(a,b)
翻译为(a,c)
。
fmap f (x,y) = (x,f y)
Bifunctor
是f
类型,任何a
和b
都可以将a->c
和b->d
两个函数应用于{{} 1}}获取f a b
。例如,f c d
是(,)
:有一种方法可以应用任意一对函数Bifunctor
和a->c
将b->d
翻译成(a,b)
(c,d)
bimap f g (x,y) = (f x, g y)
是Biapplicative
这样一种类型,f
和a
可以将b
应用于f (a->c) (b->d)
以获取f a b
}}。例如,f c d
是(,)
:有一种方法可以应用对中的任何函数将Biapplicative
转换为(a,b)
(c,d)
biap (f,g) (x,y) = (f x, g y)
将Data.Biapplicative
定义为&#34;提升&#34;一对函数biliftA2
和a->c->e
- 构造一个类型为b->d->f
和(a,b)
的两个参数的函数
(c,d)
所以biliftA2 f g = \(x,y) (z,t) -> (f x z, g y t)
构造了一个可以在biliftA2
中使用的函数来进行必要的折叠。 scanl1
将忽略前一对的第一个投影,flip const
将加上前一对和下一对的第二个投影。