在Haskell中折叠,使用多个函数

时间:2014-01-27 13:09:17

标签: haskell fold accumulate

我有一个基于字母的整数列表。例如:

let charlist = map (ord) "ABCDEF"

charlist将如下所示:

[65,66,67,68,69,70]

我还列出了三个功能:(+)(-)(*)。此示例中的列表如下所示

let funclist = [(+), (-), (*)]

我想在charlist中的元素之间按顺序应用函数(如果charlist中有更多“空格”而不是funclist中的元素},您从funclist的开头重新开始,并从左到右计算最终值 ,如下所示:

s = ((((((65) + 66) - 67) * 68) + 69) - 70)

我在考虑使用foldl,但foldl似乎只能使用一个函数。有没有其他方法可以做到这一点?如果可能的话,我想在一个函数中总结整个过程,尽管这不是必需的。

4 个答案:

答案 0 :(得分:6)

虽然foldl可能只应用一个功能,但您可以在数据中使用不同的功能。将相应的+-*函数附加到数据的技巧。你是正确的开始:

funclist = [(+), (-), (*)]

但现在让我们制作上面列表的无限版本,例如[(+), (-), (*), (+), (-), (*)...]

infinite_funclist = cycle funclist

让我们分配我们要折叠的数字。在这种情况下first65rest[66..70]

(first:rest) = [65..70]

现在我们将restinfinite_funclist压缩在一起以获得[(66,(+)), (67,(-)), (68,(*)), (69,(+)), (70,(-))]。我们从first开始,对于每个新元素,我们将当前元组的第二部分中的操作应用于当前值,第一部分如下:

result = foldl' (\acc (v, f) -> acc `f` v) first (zip rest infinite_funclist)

如果我们想要打印结果,我们可以这样做:

main = print result

(链接到代码here

答案 1 :(得分:4)

从本质上讲,这是一个拉链而不是折叠。最好的是

  

> zipWith($)(循环funclist)charlist
  [(65 +),(66-),(67 *),(68 +),(69-),(70 +)]

但由于左关联性和初始元素,我们需要做一些更多的罗嗦

  

>让ptApplied =尾巴。 zipWith(($)。flip)(循环funclist)$ charlist
  ptApplied = [(+ 66),(减去67),(* 68),(+ 69),(减去70)]

只有到了折叠

  

> foldl'(flip($))(head charlist)ptApplied

答案 2 :(得分:1)

您总是可以通过折叠的累加器传递更多信息,单个函数可以将其用于行为,就好像每次都是不同的函数一样。可能最简单的方法是将当前的函数列表传递给累加器中列表的其余部分。

Prelude Data.List> snd $ foldl' (\(f:fs, acc) x -> (fs, f acc x))
                                ((+):cycle funclist, 0) [65,66,67,68,69,70]
4351

(我在funclist的前面插入了一个额外的(+),以便“真实”加上介于65和66之间,而不是在初始累加器0和65之间。

答案 3 :(得分:0)

谁说你不能“将变量”传递给foldl?

Prelude> let f = [(+), (-), (*)]

Prelude> let c = [65,66,67,68,69,70]

Prelude> foldl (\(a,i) val -> ((f!!(mod i 3)) a val,i + 1)) (head c,0) (tail c)
(4351,5)