iT邦幫忙

2023 iThome 鐵人賽

DAY 11
1

剛學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,這個實驗設計方法與柯里化有異曲同工之妙,都是為了簡化影響因子,避免多個變因的交互作用會讓事情變得更複雜,難以分析及掌控,原來很多事情的道理其實都是相通的!

今日結論

雖說好像能稍微理解柯里化是在幹嘛,但實際上要靈活應用感覺還有一段路,像是剛看了一個用柯里化寫累加陣列的例子,完全不行...那麼今天就到這草草結束(遮臉)

Reference

Proessor Frisby's Mostly Adequate Guide to Functional Programming 中譯
What Is Currying in Programming?-Spice up your code with currying
[FP] Currying的意義


上一篇
閉包和他的快樂小夥伴scope chain
下一篇
物件導向概念
系列文
超低腦容量學習法遇到javascript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言