上一篇關於Currying的介紹,咱們提到F#是如何作Currying變換的:編程
let addWithThreeParameters x y z = x + y + z let intermediateFn1 = addWithThreeParameters 1
給定一個接受三個參數的函數addWithThreeParameters
,咱們經過app
let intermediateFn1 = addWithThreeParameters 1
這樣的方式建立出了一個新的函數intermediateFn1
,其函數簽名爲:函數式編程
int -> int -> int
上面是F#用來描述函數簽名的方式,它表示函數接受兩個int類型的參數,返回類型爲int類型。
相似地:函數
(int -> int) -> int
表示參數爲(int -> int)
類型的函數,返回類型爲int;而(int -> int)
又是一個函數,表示接受一個int類型的參數,返回類型仍然爲int。學習
對於F#而言,函數自己須要接受三個參數,可是咱們調用的時候只給一個參數,從而建立出接受兩個參數的新函數,這種方式被稱做是Partial application
。也就是說咱們經過Partial application
的方式完成了Currying。
Partial application
是經常使用的函數式編程風格,對於初學者而言也很重要。咱們在Currying一節介紹過Curring的目的是爲了生成一個只接受一個參數的新函數,從而能夠將兩個函數粘結在一塊兒。
那麼Partial application
就是F#完成Curring的一種手段。設計
還記得C#版本的Currying嗎?咱們是通純手工方式建立了新的Currying函數。code
public Func<int, int> AddWithTwoParameters(int x) { Func<int, int> subFunction = y => x + y; return subFunction; }
在C#裏面函數式無法經過只傳遞一個參數的方式來生成一個新的函數,在C#中聲明一個三個參數的函數,調用的時候只傳入一個參數會編譯出錯,這是衆所周知的。
固然,非要用C#演示Partial application
,咱們能夠用一種不天然的方式來作到:blog
public static Func<T2, T3, TR> Apply<T1, T2, T3, TR> (Func<T1, T2, T3, TR> function, T1 arg1) { return (arg2, arg3) => function(arg1, arg2, arg3); } //調用 Func<int, int, int> add = (a, b) => a + b; var add5 = Apply(add, 5); var add51 = add5(1);
F#是這樣作的:接口
let add5 = (+) 5 // partial application let add51= add5 1
若是說Partial application
還能夠用C#來勉強實現,後面描述的函數式特性幾乎不會出如今OO風格的代碼裏,因此後面的章節大都會以F#來演示。string
Partial application
之因此在函數式編程中佔有很重要的地位,他不單單可以完成Curring變換,還能夠將函數變成一個可重用的組件,考慮下面的代碼:
[1;2;3] |> List.map add51
咱們將add51
這個新函數應用到了[1;2;3]這個list中的每一個元素中。
下面的這個例子更復雜一些,用來演示經過Partial application
來完成OO範式中的Dependency Injection
功能。
//建立一個調用add函數,而且能夠注入logger實現的函數 let addWithPluggableLogger logger x y = let result = x + y logger "x+y" result result // 建立一個consoleLogger let consoleLogger argName argValue = printfn "%s=%A" argName argValue //把addWithConsoleLogger作partial應用,把consoleLogger應用在上面,同時建立出一個具備添加log能力 //的add函數,他的函數簽名爲`int -> int -> int`,跟普通的add函數式一致的, //可是此刻他擁有了添加log的能力: let addWithConsoleLogger = addWithPluggableLogger consoleLogger addWithConsoleLogger 1 2 addWithConsoleLogger 42 99
也許你已經看出來函數參數的順序決定可否Partial application
, 由於在作Partial
應用的時候老是按照參數從左到右的順序執行的,你沒法把一個參數應用在函數的最後一個位置。
下節將會描述如何設計函數讓其可以支持Partial application
,以及F#中的管道符|>
的用法。想學習函數式編程的同窗能夠持續關注。