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

在Haskell中折叠,使用多个函数,haskell,fold,accumulate,Haskell,Fold,Accumulate,我有一个基于字母的整数列表。例如: let charlist = map (ord) "ABCDEF" charlist将如下所示: [65,66,67,68,69,70] s = ((((((65) + 66) - 67) * 68) + 69) - 70) 我还有三个函数的列表:(+)、(-)和(*)。本例中的列表如下所示 let funclist = [(+), (-), (*)] 我想在charlist中的元素之间按顺序应用函数(如果charlist中的“空格”比funclist

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

let charlist = map (ord) "ABCDEF"
charlist
将如下所示:

[65,66,67,68,69,70]
s = ((((((65) + 66) - 67) * 68) + 69) - 70)
我还有三个函数的列表:
(+)
(-)
(*)
。本例中的列表如下所示

let funclist = [(+), (-), (*)]
我想在
charlist
中的元素之间按顺序应用函数(如果
charlist
中的“空格”比
funclist
中的元素多,则从
funclist
的开头重新开始)并从左到右计算最终值,例如:

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

我正在考虑使用
foldl
,但是
foldl
似乎只适用于一个函数。还有别的办法吗?如果可能的话,我想在一个函数中总结整个过程,尽管这不是一个要求。

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

>zipWith($)(循环函数列表)字符列表
[(65+,(66-,(67*),(68+,(69-,(70+)]

但是由于左关联性和初始元素,我们需要做得更详细一些

>让ptApplied=tail。zipWith(($).flip)(循环函数列表)$charlist
p应用=[(+66),(减去67),(*68),(+69),(减去70)]

只有到那时,折叠才会出现

>应用foldl'(翻转($)(标题列表)


虽然
foldl
只能应用一个函数,但您可以在数据中使用不同的函数。技巧是将适当的
+
-
*
函数附加到数据。你的出发点是对的:

funclist = [(+), (-), (*)]
但是现在让我们为上面的列表创建一个无限版本,比如
[(+),(-),(*),(+),(-),(+),(-),(*)…]

infinite_funclist = cycle funclist
让我们指定要在这里折叠的数字<代码>第一个在本例中是
65
其余
[66..70]

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

result = foldl' (\acc (v, f) -> acc `f` v) first (zip rest infinite_funclist)
如果我们想要打印结果,我们可以这样做:

main = print result
(链接到代码)

谁说你不能将变量“传递”给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)

您总是可以通过折叠的累加器传递更多信息,您的单个函数每次都可以使用该累加器来表现为不同的函数。可能最简单的方法是将当前要应用的函数列表传递给累加器中列表的其余部分

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之间)

我建议您首先尝试使用模式匹配和显式递归来实现这一点。一旦你有了一个有效的解决方案,还有时间来看看它是否适合高阶函数的模式,例如
foldl
。你可能想使用
cycle
,以便实现当元素用完时从
funclist
开始重新开始的功能。我喜欢你的答案;这有助于简化我的想法。谢谢你!这很好用。直截了当的解决方案,有很好的解释,即使像我这样的新手也能理解。;)