點燈坊

失くすものさえない今が強くなるチャンスよ

Haskell 之 Higher Order Function

Sam Xiao's Avatar 2020-02-05

Haskell 支援 First Class Function,所以可將各 Function 相同部分抽成 Higher Order Function,不同部分亦抽成小 Function,最後以 Argument 傳入產生各 Function。

Version

Haskell for Mac 1.8.2

Named Function

ifEvenInc x = 
  if even x
  then x + 1
  else x
              
ifEvenDouble x = 
  if even x
  then x * 2
  else x
  
ifEvenSquare x =
  if even x
  then x ^ 2
  else x 

ifEvenInc 4
ifEvenDouble 4
ifEvenSquare 4  

我們有 ifEvenIncifEvenDoubleifEvenSquare 三個 function ,都判斷 parameter 是否為偶數,若是則執行不同 expression,否則都回傳原來值。

我們發現這三個 function 非常類似,唯一差別只有 parameter 為偶數時的回傳不同 expression。

even 為 Haskell 內建 function,可直接使用

argument000

Higher Order Function

inc x = x + 1
double x = x * 2
square x = x ^ 2

ifEven f x = 
  if even x
  then f x
  else x
  
ifEvenInc x = ifEven inc x
ifEvenDouble x = ifEven double x
ifEvenSquare x = ifEven square x

ifEvenInc 4
ifEvenDouble 4
ifEvenSquare 4

可將不同 expression 單獨抽出來成為 function,ifEven 的第一個 argument 以 function 傳入。

arg001

Point-free

inc x = x + 1
double x = x * 2
square x = x ^ 2

ifEven f x = 
  if even x
  then f x
  else x
  
ifEvenInc = ifEven inc
ifEvenDouble = ifEven double
ifEvenSquare = ifEven square

ifEvenInc 4
ifEvenDouble 4
ifEvenSquare 4

可發現 ifEvenIncifEven 最後一個 argument 都是 x,可同時兩邊消去 x,使 ifEven 改回傳 function。

只有 curry function 才允許 = 兩邊相同 argument 消去

arg003

Lambda Function

ifEven f x = 
  if even x
  then f x
  else x
  
ifEvenInc = ifEven (\x -> x + 1)
ifEvenDouble = ifEven (\x -> x * 2)
ifEvenSquare = ifEven (\x -> x ^ 2)

ifEvenInc 4
ifEvenDouble 4
ifEvenSquare 4

除了 named function 外,對於只使用一次的 function,亦可使用 lambda function 取代。

arg002

Conclusion

  • 由本文可發現 Haskell 定義 curry function 與呼叫 function 都使用 space 的方便,當 = 左右兩側的 argument 相同時,可以很直覺的發現並消去
  • 還可發現 curry function 的妙用,對於重構成 higher order function 的直覺與方便,這也是為什麼 FP 預設都使用 curry function