1. 程式人生 > >函數式編程之-組合函數

函數式編程之-組合函數

實現 mage 並不是 表達 image 表示 中綴 har 分享

組合

函數式編程的核心在於組合,其中之一就是如何組合函數。我們在Currying一文就提到過組合,我們當時是這樣描述的:只有一個輸入和一個輸出的函數才能完成組合,當然並不是所有的函數都只有一個輸入,Currying可以幫助我們把多個輸入參數的函數變成只有一個輸入的函數。
那麽到底什麽是組合,怎麽組合?
給定下面的兩個函數:
技術分享圖片
組合上面的兩個函數:
技術分享圖片
變成下面的函數:
技術分享圖片
看個例子:

let add1 x = x + 1 
let multiply2 x = x * 2
let compose g f x = f(g(x))

對應的函數類型為:

add1 : x:int -> int
multiply2 : x:int -> int
compose : g:('a -> 'b) -> f:('b -> 'c) -> x:'a -> 'c

通過compose函數來把add1和multiptly2組合起來:

let add1ThenMultiply2 x = compose add1 multiply2

技術分享圖片
從而得到新的函數:
技術分享圖片

let result = add1ThenMultiply2 10

技術分享圖片
既然compose這個函數在F#這麽常用,不如定義一個操作符>>來表示:

let (>>) f g x = g ( f(x) )

因此上面的代碼也可以通過>>來組合:

let add1ThenMultiply2 x = (>>) add1 multiply2

由於操作符支持中綴表達式,也即操作符可以寫在兩個參數的中間,例如+號:

(+) 1 3

實際上可以寫為:

1 + 3

那麽上面的代碼就可以寫成:

let add1ThenMultiply2 x = add1 >> multiply2

組合和管道符的區別

上面的例子我們還可以用管道符來實現:

let result1 = 10 |> add1 |> multiply2

管道符和組合的定義看起來非常相似:

let (|>) x f = f x
let (>>) f g x = g ( f(x) )

管道符(|>)接受兩個參數,在往下一個管道符傳遞的時候已經完成了求值,而函數組合實際上生成了新的函數,最後一步傳入實際的參數才會完成求值。

下面的圖示描述了管道符的求值過程:
技術分享圖片

函數式編程之-組合函數