3 回答
TA貢獻1827條經驗 獲得超8個贊
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
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個(或更多)輸入。
即使它們都返回一個函數作為輸出,返回的函數也是完全不同的形式,如上所示。
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時,它使用其參數以及部分應用的值來創建結果。
添加回答
舉報
