什么是F#


作者:Alexey Bykov@EastBancTech
原文:http://bit.ly/1nGroOz
翻譯:kk1982.com
轉載請注明

 

簡介

F#是由微軟研究團隊為.NET平台研發的一種現代函數式語言。該語言自從2005年開始研發,到2013年12月份發布了3.1版本。F#最開始只是一個學術研究項目,經過若干年的發展,已經成為了一門成熟的語言,並被眾多商業公司所使用,尤其在財務領域。

之所以要研發一門與C#大為不同的語言的原因:

  • 函數范式比面向對象更適合數據計算與操作;
  • 能夠使用那些在C#里由於設計理念不同而無法實現的編程概念;
  • 避免C#的一些繼承性設計問題,這些問題由於C#已經廣泛應用而無法調整了。

從語言特性的角度來說,F#是C#的超集,因此C#能做的事情F#也能做,但反之則非亦然,F#有很多事情C#做不了。

在F#與其他.NET語言之間有着完整的互通性。當F#被編譯成程序集后,就可以被任何一種.NET語言使用,包括C#和VB.NET等。這也意味着F#的代碼可以跟系統中以C#寫成的部分和平共處。

F#相對於C#的優勢

Option取代NULL引用

C#有項危險的特性就是允許使用NULL值替代對象,這個特性是一大批易於產生而難於檢測的Bug的來源,為了避免此類錯誤而在代碼中到處增加的檢查又降低了代碼的可讀性。

F#並不允許NULL值,取而代之的是使用option。與C#一樣,option在表示缺失對象值上與NULL值意義相同,但是卻能保證安全性。

代數數據類型(Algebraic Data Type)

C#對於代數數據類型(ADT)沒有完整的支持,這種數據類型可以用簡單的數據結構組成更為復雜的結構。C#所使用的類型是由類與結構構成的,對於Sum類型的支持極為有限,僅由枚舉形式來體現。

相對的,F#對於ADT有着全面的支持,這使得其能夠更為精准地以數據結構的角度去描述業務實體,減少誤解數據含義的幾率,從而提高代碼質量。通常,F#可以通過不呈現的手段來避免不想要的情況,這樣就沒有可能去寫出不合適的代碼來。

變換(Transformation)與變動(Mutation)

C#鼓勵更改數據以及使用狀態機制,這代表着一旦對象被創建,就要在其生命周期內經歷一系列的修改以改變其狀態。依據對象當前狀態的不同,可以允許對其執行或者不允許執行部分操作。要想安全地使用該對象,必須先對其進行狀態檢查,以確保處於正確的狀態下,如果不這樣做,很可能就會產生不可預計的結果甚至於產生崩潰的Bug。

而對於F#來說,則鼓勵使用變換而非可變體。變換並不會修改對象,因此也不會更改其狀態。F#會創建一個新對象並將值傳遞過去,以保持原對象的完整。這也意味着一個對象會一直保持着其被創建時的狀態。只跟一個單一的狀態打交道可以極大地簡化開發過程,並減少代碼量,因為當我們看到一個對象時,我們知道它一定只處於一種可能的狀態下,因此不需要做額外的檢查就可以安全地使用它。

表達式(Expression)與語句(Statement)

因為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世界里的著名解析器生成工具LexYacc來命名的。FsLex和FsYacc有着豐富的診斷能力,可以參與整個構建以簡化開發過程。

F#的缺點

以下缺點僅當從函數式編程所習慣的准則去使用F#時才存在,如果你選擇不使用這些准則,那么這些缺點也就不存在了。

陡峭的學習曲線

對於一個從未接觸過函數式編程的人來說,用一種全新的思考方式來進行F#編程很可能是一個挑戰。

更為復雜的數據結構

在使用變換而非變動的概念之下,需要使用更高級的數據結構才能更加有效率地操作數據。舉個例子,在F#中你要使用二叉樹而非C#中的哈希表。其他例子還有可能會大量使用拉鏈結構而非遍歷器。

垃圾回收器負載重

使用變換而非變動的概念會導致創建比實際需要多的對象,這些對象需要及時被銷毀,因此與只更改狀態的對象相比,垃圾回收器的負擔要大得多。開發人員需要在這之中謹慎地尋找一個平衡。

命名更有難度

F#不像C#那樣允許對方法進行重載,所以在F#同一模塊里的兩個函數不能有一樣的名字,這樣就導致對函數進行唯一命名比較困難。制定一個統一的F#命名規范不是一件容易的事情。

缺乏高級工具

微軟在為C#程序員打造工具上花費了大力氣,很不幸,F#就沒有那么多工具可供使用,這使得編碼就不是那么舒服。F#連基本的重構工具都沒有。

不是所有項目類型都適用

舉一個不錯的例子,開發帶界面的應用程序對於F#來說就比較尷尬,因為操縱控件必須要更改其狀態的,而這不是F#所擅長的事情。

總結

F#是一個現代的函數式編程語言,被設計作為面向對象編程的C#及VB語言的備選。F#從后者中繼承了優秀的特性,並拋除那些危險的特性。這是為什么寫F#代碼更為安全並且易於維護。盡管部分項目類型不是F#的強項,但是對於那些進行密集數據計算的項目絕對應該是首選。F#對於業務問題的描述要比C#精准的多,使得其很適合作為服務端應用的候選。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM