Higher Order Functions


Posted by TempuraEngineer on 2023-08-27

目錄


HOF是什麼

Higher Order Functions(HOF)是一種functional programming的技巧,它是一個接收function,並回傳function的function

const nums = [1,2,3,4,5,6,70,8];

// 陣列的filter是JS內建的HOF
nums.filter((n) => n > 10);

const filter = (fn) => {
  return (arr) => {
    return fn(arr)
  };
}

// currying和partial也是HOF
const curriedSum = (n1) => {
  return (n2) => {
    return n1 + n2;
  }
}

// filterLarger100也是HOF
const filterLarger100 = filter((arr) => {
    const res = [];

    arr.forEach((i) => {
        if(i > 100){
            res.push(i);
        }
    })

    return res;
});

filterLarger100([12,33,120,11]);

巧妙運用的話HOF甚至可以形成一條chain(pipeline function)


為什麼要用HOF

HOF的核心概念是組合(composition),以提高複用性(reusability)

也就是把每個function根據各自的職責拆開來、將共用的部分抽象化,以便重複使用,使用時再根據需求將function組合再一起

舉例來說,如果我們需要計算數字的加、減

在不使用HOF的情況可能會長這樣,或者是一個function內有判斷式,利用判斷式決定要執行哪段code

const increaseNums = (data, operatedNum) => {
  return data.map((d) => d + operatedNum);
}

const decreaseNums = (data, operatedNum) => {
  return data.map((d) => d - operatedNum);
}

console.log(increaseNums(nums, 1)); // [11, 21, 51] 

console.log(decreaseNums(nums, 20)); // [-10, 0, 30]

使用HOF的話則會像以下這樣

type CalculateFunction = (originalNumber:number, operatedNumber:number) => number;

// HOF + partial
const calculate = (calculateFn:CalculateFunction) => {
  return (data:number[], operatedNum:number) => {
    return data.map((d) => calculateFn(d, operatedNum));
  }
}

const increaseNums = calculate(increase);
const decreaseNums = calculate(decrease);

console.log(increaseNums(nums, 1)); // [11, 21, 51] 

console.log(decreaseNums(nums, 20)); // [-10, 0, 30]


compose

compose function會接收一個或多個function,然後由左而右將function組合起來,其中最左邊的function可以接收任意數量的參數

一但最左側的functionc回傳了值其右邊的function會接收這個回傳值,並進行一些計算後再回傳另一個值直到所有function都跑過

type CalculateFunction = (originalNumber:number, operatedNumber?:number) => number;

const compose = (fn:CalculateFunction, ...fns:CalculateFunction[]) => {
  return (...num: number[]) => {
    // 迭代第二個function開始的一連串陣列
    return fns.reduce((res, currFn, index) => {
      //  將前一個function的回串值作為第一個引數,傳給目前的function做計算,第二個引數為index + 2的元素是因為前面兩已經用在第一個function了
      return currFn(res, num[index + 2]);

    }, fn.apply(this, [num[0], num[1]])); // 使用apply呼叫第一個function,並把前兩個參數傳進去,將其回傳值作為初始值
  }
}

用起來會像這樣

const add = (a:number, b:number = 0) => a + b;
const devide = (a:number, b:number = 0) => a - b;
const multiply = (a:number, b:number = 1) => a * b;
const halfOff = (a:number) => a / 2;
const square = (a:number) => Math.pow(a, 2);
const getSquareRoot = (a: number) => (a) => Math.sqrt(a);

// 上底加下底、乘以高、除以2
const getTrapezoidArea = compose(add, multiply, halfOff);

// 底乘以高、除以2
const getTriangleArea = compose(multiply, halfOff);

// 短邊平方加上長邊平方、開根號
const getHypotenuseOfTriangle = compose((a, b = 1) => suqare(a) + square(b), getSquareRoot);

// 加總
const getSum = compose(add, add, add,  add);

// 乘總
const getProduct = compose(multiply, multiply, multiply);

console.log(getTrapezoidArea(5, 7, 6)); // 36
console.log(getTriangleArea(7, 6)); // 21
console.log(getHypotenuseOfTriangle(3, 4)); // 5

console.log(getSum(1, 2, 3, 4, 5)); // 15
console.log(getProduct(2, 2, 2, 2)); // 16


參考資料

Functional Programming — Higher Order Function, HOF
Higher-Order Functions(HoF) in JavaScript - Explain Like I'm Five
Compose and Pipe in JavaScript


#HOF #compose #Functional Programming







Related Posts

實物選擇權理論應用於發電項目:A Review

實物選擇權理論應用於發電項目:A Review

SQL Injection 的攻擊原理和防範方法

SQL Injection 的攻擊原理和防範方法

有感而發的一天

有感而發的一天


Comments