函數式編程的核心在於組合
,其中之一就是如何組合函數。咱們在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#這麼經常使用,不如定義一個操做符>>
來表示:3d
let (>>) f g x = g ( f(x) )
所以上面的代碼也能夠經過>>來組合:code
let add1ThenMultiply2 x = (>>) add1 multiply2
因爲操做符支持中綴表達式,也即操做符能夠寫在兩個參數的中間,例如+號:blog
(+) 1 3
實際上能夠寫爲:ip
1 + 3
那麼上面的代碼就能夠寫成:class
let add1ThenMultiply2 x = add1 >> multiply2
上面的例子咱們還能夠用管道符來實現:im
let result1 = 10 |> add1 |> multiply2
管道符和組合的定義看起來很是類似:
let (|>) x f = f x let (>>) f g x = g ( f(x) )
管道符(|>)接受兩個參數,在往下一個管道符傳遞的時候已經完成了求值,而函數組合實際上生成了新的函數,最後一步傳入實際的參數纔會完成求值。
下面的圖示描述了管道符的求值過程: