剛學js的時候,常常會看到自己難以理解的東西,比如說這個:
function add(a) {
return function (b) {
return function (c) {
return a + b + c;
};
};
}
const result = add(1)(2)(3);
console.log(result);
明明就簡單的相加,寫成這樣倒底是想嚇誰?!
直到那天親身經歷了一件事,才知道是自己之前太天真...
這是在寫練習題的時候發生的...我想將使用者輸入的東西,先做了驗證,確保程式拿到的輸入是我預設的資料格式,所以寫了一個函式validateInput,argument是使用者輸入的值&驗證的條件(以物件的形式,物件中的每個key是驗證規則的名稱,value則是一個驗證函式)。這個函式會把input丟進每一個驗證規則。
const validateInput = function (input, testCondition) {
const values = Object.values(testCondition); //obj->array
for (const fn of values) {
fn(input);
}
};
其中有一個驗證條件是擋max值
const max = function (input, maxValue) {
if (input > maxValue) throw new Error(`請輸入不大於${maxValue}的值`);
return input;
};
但又希望這個max是可以依照每次使用的狀況能彈性調整,不知道該怎麼做,請教了前輩用了下面的方法:多加了一個argument(暫時叫test),將想動態調整的max引進函式裡,因為for loop跑到最後一圈才會用到這個引數,不會影響到前面的驗證條件。
const validateInput = function (input, testCondition, test) {
const values = Object.values(testCondition);
for (const fn of values) {
fn(input, test);
}
};
const maxLimit = 500;
validateInput(
input,
{
isEmptyStr,
isString,
isNagtive,
isFloat,
max,
},
maxLimit
);
後來又再請教了前前輩,才知道還有另一種寫法,當時說實在的很是震驚...但過陣子回來再看,這樣的寫法其實很合理啊(又漂亮),原來之前一直不懂的東西,是應用在這樣的情境,事情一直沒有笨蛋想的那麼簡單...而這就是所謂的柯里化。
const max = function (maxValue) {
return function (input) {
if (input > maxValue) throw new Error(`請輸入不大於${maxValue}的值`);
};
};
const validateInput = function (input, testCondition) {
const values = Object.values(testCondition);
for (const fn of values) {
fn(input);
}
};
const maxLimit = 500;
validateInput(input, {
isEmptyStr,
notNumOfStr,
isNagtive,
isFloat,
max: max(maxLimit),
});
柯里化的寫法提供了一種pre-load的特性,能將多個argument的函式,先將其中一個(或兩個)argument載入函式變成另一個新的函式
,像是上面的例子,我可以pre-load不同的max進去,創造好多個擋不同max的函式。不過實際上是不用儲存在另外一個變數裡,下面這樣寫只是為了易於理解。
const max = function (maxValue) {
return function (input) {
if (input > maxValue) throw new Error(`請輸入不大於${maxValue}的值`);
};
};
const max500=max(500) //擋>500的值
const max20000=max(20000) //擋>20000的值
What's demonstrated here is the ability to "pre-load" a function with an argument or two in order to receive a new function that remembers those arguments.
於是,在多次呼叫函式的情境當中,使用柯里化來簡化並提昇程式碼的語意,聽說,這是functional programming的精隨之一。
另外看到了一篇柯里化的意義,覺得有趣,想起以前當製程工程師的時候有接觸過的DOE,這個實驗設計方法與柯里化有異曲同工之妙,都是為了簡化影響因子,避免多個變因的交互作用會讓事情變得更複雜,難以分析及掌控,原來很多事情的道理其實都是相通的!
雖說好像能稍微理解柯里化是在幹嘛,但實際上要靈活應用感覺還有一段路,像是剛看了一個用柯里化寫累加陣列的例子,完全不行...那麼今天就到這草草結束(遮臉)
Proessor Frisby's Mostly Adequate Guide to Functional Programming 中譯
What Is Currying in Programming?-Spice up your code with currying
[FP] Currying的意義