我经常使用LINQ Aggregate
运算符。本质上,它允许您通过对函数的最后一个计算值和序列的下一个元素重复应用函数来对序列“累加”函数。
例如:
int[] numbers = ...
int result = numbers.Aggregate(0, (result, next) => result + next * next);
将计算数组元素的平方和。
在谷歌上搜索之后,我发现函数式编程中的通用术语是"fold",这让我对可以写成折叠的函数产生了好奇,换句话说,就是f = fold op
中的f
。
我认为可以用这个运算符计算的函数只需要满足(如果我错了,请纠正我):
f(x1, x2, ..., xn) = f(f(x1, x2, ..., xn-1), xn)
这处房产看起来很普通,应该有个特别的名字。有吗?
3条答案
按热度按时间o2g1uqev1#
一个Iterated binary operation可能是你正在寻找的。
您还需要添加一些停止条件,如
它们定义了一个二元运算
f
和另一个函数F
,在我提供的链接中,用来处理当你到达f(x1,x2)
时发生的事情。6l7fqoea2#
为了澄清这个问题:“平方和”是一个特殊的函数,因为它具有这样的性质,即它可以用折叠泛函加上一个λ来表示,即
哪些函数
f
具有此属性,其中dom f = { A tuples }
,ran f :: B
?显然,由于折叠的力学,f是可折叠的陈述是Assert存在一个
h :: A * B -> B
,使得对于A中的任何n〉0,x1,...,xn,f ((x1,...xn)) = h (xn, f ((x1,...,xn-1)))
。h
存在的Assert与您的条件几乎是一样的所以你几乎是正确的;不同之处在于,您需要
A=B
,这比一般的fold可表达函数要严格一些。但更有问题的是,fold一般也需要一个起始值a
,该值被设置为a = f nil
。您的公式()的错误之处在于它假设h是f在对列表上的作用,但这只在h(x, a) = a
时成立。也就是说,在平方和的例子中,你给Accumulate的初始值是0,当你添加它的时候,它是一个什么都不做的函数,但是有一些可折叠表达的函数,其中的起始值做了一些事情,在这种情况下,我们有一个不满足()的可折叠表达的函数。例如,以下面这个可折叠表达的函数
lengthPlusOne
为例:一个月11个月1x,而是一个月12个月1x。
最后,让我们给予一个列表上的函数不能用fold表示的例子。假设我们有一个黑盒函数,并在这些输入上测试它:
这样一个关于元组(=有限列表)的函数显然是存在的(我们可以定义它具有上述输出,并且在任何其他列表上为零),但是它是不可折叠的,因为(1)隐含
h(1,1)=1
,而(2)隐含h(1,1)=2
。我不知道是否有其他的术语比说'一个函数可表达为一个折叠'。也许一个(左/右)上下文无关的列表函数将是一个很好的方式来描述它?
xriantvc3#
在函数式编程中,
fold
用于聚合列表、数组、序列等集合上的结果。您对fold
的表述不正确,这会导致混淆。正确的表述可以是:对
f
的要求实际上是非常宽松的。假设元素的类型是T
,e的类型是U
。所以函数f
实际上有两个参数,第一个参数的类型是U
,第二个参数的类型是T
。并返回U
类型的值(因为这个值将再次作为函数f
的第一个参数提供)。我们有一个签名为f: U * T -> U
的“accumulate”函数。因此,我认为没有一个正式的术语来描述这类函数。在你的例子中,
e = 0
,T = int
,U = int
和你的lambda函数(result, next) => result + next * next
有一个签名f: int * int -> int
,它满足“可折叠”函数的条件。如果你想知道,
fold
的另一个变体是foldBack
,它以从xn
到x1
的相反顺序累加结果:当
fold
和foldBack
返回相同的结果时,满足f(x,y)= f(x,y)的交换函数有一些有趣的例子。关于fold
本身,它是范畴论中退化的一个具体例子。你可以阅读更多关于退化here的内容。