为了账号安全,请及时绑定邮箱和手机立即绑定

currying和部分应用有什么区别?

currying和部分应用有什么区别?

currying和部分应用有什么区别?我经常在互联网上看到各种各样的抱怨,其他人的currying例子并不是currying,但实际上只是部分应用。我没有找到关于部分应用是什么的合理解释,或者它与currying有何不同。似乎存在普遍的混淆,在某些地方将等效的例子描述为currying,在其他地方描述为部分应用。有人可以向我提供这两个术语的定义,以及它们如何区别的细节吗?
查看完整描述

3 回答

?
慕仙森

TA贡献1827条经验 获得超7个赞

Currying将n个参数的单个函数转换为n个函数,每个函数都有一个参数。鉴于以下功能:


function f(x,y,z) { z(x(y));}

咖喱变成:


function f(x) { lambda(y) { lambda(z) { z(x(y)); } } }

为了获得f(x,y,z)的完整应用,您需要这样做:


f(x)(y)(z);

许多函数式语言都可以让你写f x y z。如果你只调用f x y或f(x)(y)那么你得到一个部分应用的函数 - 返回值是一个闭包,lambda(z){z(x(y))}传入x和y的值f(x,y)。


使用部分应用程序的一种方法是将函数定义为广义函数的部分应用程序,如fold:


function fold(combineFunction, accumulator, list) {/* ... */}

function sum     = curry(fold)(lambda(accum,e){e+accum}))(0);

function length  = curry(fold)(lambda(accum,_){1+accum})(empty-list);

function reverse = curry(fold)(lambda(accum,e){concat(e,accum)})(empty-list);


/* ... */

@list = [1, 2, 3, 4]

sum(list) //returns 10

@f = fold(lambda(accum,e){e+accum}) //f = lambda(accumulator,list) {/*...*/}

f(0,list) //returns 10

@g = f(0) //same as sum

g(list)  //returns 10


查看完整回答
反对 回复 2019-08-06
?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

了解它们之间差异的最简单方法是考虑一个真实的例子。假设我们有一个函数Add,它将2个数字作为输入并返回一个数字作为输出,例如Add(7, 5)返回12。在这种情况下:

  • 使用Add部分应用函数7将为我们提供一个新函数作为输出。该函数本身需要1个数字作为输入并输出一个数字。因此:

    Partial(Add, 7); // returns a function f2 as output
                     // f2 takes 1 number as input and returns a number as output

    所以我们可以这样做:

    f2 = Partial(Add, 7);f2(5); // returns 12;
           // f2(7)(5) is just a syntactic shortcut
  • 哗众取宠的功能Add会给我们一个新的功能输出。该功能本身需要1号作为输入,并输出另一个新的功能。然后第三个函数将1个数作为输入并返回一个数作为输出。因此:

    Curry(Add); // returns a function f2 as output
                // f2 takes 1 number as input and returns a function f3 as output
                // i.e. f2(number) = f3
                // f3 takes 1 number as input and returns a number as output
                // i.e. f3(number) = number

    所以我们可以这样做:

    f2 = Curry(Add);f3 = f2(7);f3(5); // returns 12

换句话说,“currying”和“partial application”是两个完全不同的功能。Currying只需1个输入,而部分应用需要2个(或更多)输入。

即使它们都返回一个函数作为输出,返回的函数也是完全不同的形式,如上所示。


查看完整回答
反对 回复 2019-08-06
?
GCT1015

TA贡献1827条经验 获得超4个赞

注意:这是从F#Basics中获取的,这是.NET开发人员进入函数式编程的优秀介绍性文章。

Currying意味着将具有许多参数的函数分解为一系列函数,每个函数都接受一个参数并最终产生与原始函数相同的结果。对于功能编程新手来说,Currying可能是最具挑战性的话题,特别是因为它经常与部分应用混淆。您可以在此示例中看到两者都在工作:

let multiply x y = x * y    let double = multiply 2let ten = double 5

您应该立即看到与大多数命令式语言不同的行为。第二个语句通过将一个参数传递给一个带两个的函数来创建一个名为double的新函数。结果是一个函数,它接受一个int参数并产生相同的输出,就好像你已经调用了multiply,x等于2,y等于那个参数。在行为方面,它与此代码相同:

let double2 z = multiply 2 z

通常,人们错误地认为乘法是形成双重的。但这只是有点真实。乘法函数是curry,但是在定义时会发生这种情况,因为默认情况下F#中的函数是curry。当创建双重函数时,更准确地说,部分应用了乘法函数。

乘法函数实际上是一系列两个函数。第一个函数接受一个int参数并返回另一个函数,有效地将x绑定到特定值。此函数还接受一个int参数,您可以将其视为绑定到y的值。在调用第二个函数之后,x和y都被绑定,因此结果是x和y的乘积,如double体中所定义。

要创建double,将计算乘法函数链中的第一个函数以部分应用乘法。结果函数的名称为double。当计算double时,它使用其参数以及部分应用的值来创建结果。


查看完整回答
反对 回复 2019-08-06
  • 3 回答
  • 0 关注
  • 443 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信