做者:Alexey Bykov@EastBancTech
原文:http://bit.ly/1nGroOz
翻譯:kk1982.com
轉載請註明git
F#是由微軟研究團隊爲.NET平臺研發的一種現代函數式語言。該語言自從2005年開始研發,到2013年12月份發佈了3.1版本。F#最開始只是一個學術研究項目,通過若干年的發展,已經成爲了一門成熟的語言,並被衆多商業公司所使用,尤爲在財務領域。程序員
之因此要研發一門與C#大爲不一樣的語言的緣由:github
從語言特性的角度來講,F#是C#的超集,所以C#能作的事情F#也能作,但反之則非亦然,F#有不少事情C#作不了。算法
在F#與其餘.NET語言之間有着完整的互通性。當F#被編譯成程序集後,就能夠被任何一種.NET語言使用,包括C#和VB.NET等。這也意味着F#的代碼能夠跟系統中以C#寫成的部分和平共處。express
C#有項危險的特性就是容許使用NULL值替代對象,這個特性是一大批易於產生而難於檢測的Bug的來源,爲了不此類錯誤而在代碼中處處增長的檢查又下降了代碼的可讀性。編程
F#並不容許NULL值,取而代之的是使用option。與C#同樣,option在表示缺失對象值上與NULL值意義相同,可是卻能保證安全性。安全
C#對於代數數據類型(ADT)沒有完整的支持,這種數據類型能夠用簡單的數據結構組成更爲複雜的結構。C#所使用的類型是由類與結構構成的,對於Sum類型的支持極爲有限,僅由枚舉形式來體現。數據結構
相對的,F#對於ADT有着全面的支持,這使得其可以更爲精準地以數據結構的角度去描述業務實體,減小誤解數據含義的概率,從而提升代碼質量。一般,F#能夠經過不呈現的手段來避免不想要的狀況,這樣就沒有可能去寫出不合適的代碼來。編程語言
C#鼓勵更改數據以及使用狀態機制,這表明着一旦對象被建立,就要在其生命週期內經歷一系列的修改以改變其狀態。依據對象當前狀態的不一樣,能夠容許對其執行或者不容許執行部分操做。要想安全地使用該對象,必須先對其進行狀態檢查,以確保處於正確的狀態下,若是不這樣作,極可能就會產生不可預計的結果甚至於產生崩潰的Bug。模塊化
而對於F#來講,則鼓勵使用變換而非可變體。變換並不會修改對象,所以也不會更改其狀態。F#會建立一個新對象並將值傳遞過去,以保持原對象的完整。這也意味着一個對象會一直保持着其被建立時的狀態。只跟一個單一的狀態打交道能夠極大地簡化開發過程,並減小代碼量,由於當咱們看到一個對象時,咱們知道它必定只處於一種可能的狀態下,所以不須要作額外的檢查就能夠安全地使用它。
由於C#依賴於狀態與變更,所以作變更的順序就變得額外地重要,兩條語句的位置互換均可能會產生Bug,所以在C#中語句的順序是另一件須要考慮的事情。相反,一個F#程序本質上來講就是一個由較小表達式拼成,且將輸入值映射到部分輸出值上的大表達式。表達式哪一部分先被計算並不重要,由於在一個無反作用的計算模型下,計算的順序並不影響結果。所以從寫語句轉變到用表達式編程能夠確保不會由於語句順序錯誤而產生Bug。
C#經過在類與結構之下同時建立屬性與方法的形式鼓勵混合數據與邏輯,可是在進行序列化的時候,邏輯就須要被剔除,這也是爲什麼當須要序列化的時候,類的數據要被轉移到沒有邏輯的純數據對象上。
函數編程語言建議你不要將數據和邏輯混合在一塊兒,這樣當序列化爲JSON或者XML時就更爲直觀與容易。
C#的語法略囉嗦,對於同一件事情的表達,C#寫的代碼要比F#多得多。C#的囉嗦尤爲表如今爲方法的參數和返回值指定類型上。F#有一個高級類型推斷系統,能夠經過數值是怎樣被使用的而推斷出這些數值的類型,所以在大部分狀況下推薦不要輸入類型而讓F#自行推斷。錄入的內容少了,生產力就提升了,代碼也得到了更好的可維護性。一些人認爲F#的語法更爲優雅更易閱讀。
C#中文件,類以及方法聲明的順序並不重要,而對於F#來講,聲明的順序則嚴格取決於文件的順序,所以你沒法引用或使用還沒有聲明的東西。這看起來像是沒必要要的設計,但實際上是一件好事兒,由於這能夠強制程序員遵照規範。
現代的面向對象設計準則,被稱之爲SOLID,在C#中能夠輕易地違反,因此才須要瞭解規範並嚴格地遵循。可是,基本一樣的準則倒是函數式編程天生即有的。所以F#從一開始就以正確的方式編碼,而寫出不良的設計反而須要故意爲之才行。
在C#中並行運行代碼不是件容易的事情,由於存在競態條件,會在兩個線程試圖同時修改同一個對象時產生。F#徹底消滅了這個問題,由於它不容許對象在建立後進行修改,當須要修改對象時,須要對原對象應用一個變換而建立一個新對象,這意味着在F#中不須要作太多事情就能夠直接運行並行代碼。
在F#中,邏輯的基礎單位是函數,在C#中則是類。函數在F#中是「頭等公民」,所以能夠做爲參數傳遞給其餘函數或者做爲函數的返回值。寫一個函數比寫一個類要省事兒,所以能夠實現一個良好的模塊化設計,以及以較低成本實現一個較爲複雜的組合場景。用這種方式寫出的代碼更加易於維護而且易於重構。
F#鼓勵使用泛型類型而非具體類型。爲泛型類型所寫的算法能夠做用於具體的類型如數字,字符串以及複雜對象。用一個泛型的實現去替代多個不一樣的類型可以使得代碼複用性更高,出錯的概率更小。
F#有一種特別的機制,用一種便捷統一的方式來處理異質數據源的數據,稱做類型提供程序。類型提供程序抽象了不一樣來源的數據的實現細節,確保類型安全,公開設計良好的標準接口。同時還具有類型按需發現功能,只有在須要時纔會載入新的類型。在這裏有一個代碼庫,存放着針對不一樣數據源的數據提供程序,並由社羣維護保持其持續更新。類型提供程序經過從不一樣數據源獲取數據的能力,爲開發帶來了信息豐富的編程。
F#有着兩個標準工具:FsLex以及FsYacc,用於基於一個正式語法來生成解析器。這倆工具是根據Unix世界裏的著名解析器生成工具Lex和Yacc來命名的。FsLex和FsYacc有着豐富的診斷能力,能夠參與整個構建以簡化開發過程。
如下缺點僅當從函數式編程所習慣的準則去使用F#時才存在,若是你選擇不使用這些準則,那麼這些缺點也就不存在了。
對於一個從未接觸過函數式編程的人來講,用一種全新的思考方式來進行F#編程極可能是一個挑戰。
在使用變換而非變更的概念之下,須要使用更高級的數據結構才能更加有效率地操做數據。舉個例子,在F#中你要使用二叉樹而非C#中的哈希表。其餘例子還有可能會大量使用拉鍊結構而非遍歷器。
使用變換而非變更的概念會致使建立比實際須要多的對象,這些對象須要及時被銷燬,所以與只更改狀態的對象相比,垃圾回收器的負擔要大得多。開發人員須要在這之中謹慎地尋找一個平衡。
F#不像C#那樣容許對方法進行重載,因此在F#同一模塊裏的兩個函數不能有同樣的名字,這樣就致使對函數進行惟一命名比較困難。制定一個統一的F#命名規範不是一件容易的事情。
微軟在爲C#程序員打造工具上花費了大力氣,很不幸,F#就沒有那麼多工具可供使用,這使得編碼就不是那麼舒服。F#連基本的重構工具都沒有。
舉一個不錯的例子,開發帶界面的應用程序對於F#來講就比較尷尬,由於操縱控件必需要更改其狀態的,而這不是F#所擅長的事情。
F#是一個現代的函數式編程語言,被設計做爲面向對象編程的C#及VB語言的備選。F#從後者中繼承了優秀的特性,並拋除那些危險的特性。這是爲何寫F#代碼更爲安全而且易於維護。儘管部分項目類型不是F#的強項,可是對於那些進行密集數據計算的項目絕對應該是首選。F#對於業務問題的描述要比C#精準的多,使得其很適合做爲服務端應用的候選。