内容简介:F# 並不是一個新語言,早在 2005 年就已經發行 1.0,隨著 .NET Core 的跨平台,也將 F# 帶進了 .NET Core,既然在 .NET Core 我們已經有了 C#,為什麼要關注 F# 呢 ?macOS High Sierra 10.13.3.NET Core 2.1.4
F# 並不是一個新語言,早在 2005 年就已經發行 1.0,隨著 .NET Core 的跨平台,也將 F# 帶進了 .NET Core,既然在 .NET Core 我們已經有了 C#,為什麼要關注 F# 呢 ?
Version
macOS High Sierra 10.13.3
.NET Core 2.1.4
F# 4.1
FSharp 的歷史
F# 並不像 C-style 語言,反而比較像 Python,事實上 F# 是從 ML、OCaml、 Python 、Haskell、Scala、Erlang … 等語言獲得靈感,除了 Python 大家較為熟悉外,剩下的都是 Functional Programming Language,由此可見 F# 的 F 就是 F
untional,所以 F# 號稱是 function first language,也就是 F# 雖然也支援 OOP,但 FP 是其主要特色。
個人大概在 2010 年曾經接觸過 F#,當初的感覺 F# 是個 外星語言
,很難體會 F# 的優點在哪裡,學沒多久就放棄了,但經過這幾年 Laravel Collection、JavaScript 、Linq 、Rx.js 與 AWS Lambda 的轟炸,越來越覺得 FP 的可愛,OOP 也能藉由 FP 手法,產生出現更優雅的實作方式。
這幾年一直想尋找一個 FP 語言來練習,期間摸過 Elixir 、Scala、Clojure,但成效一直有限,一直到最近複習 F#,才發現 F# 是一個很簡單的 FP 語言,以前看不懂的地方,瞬間都看懂了,只是當年還無法欣賞 F#。
Functional Programming 定義
一個語言要能實現 FP,必須有 4 個條件:
- 能將 function 指定為變數
- 能將 function 存到 collection 內
- 能將 function 以參數型式傳入 function
- 能在 function 回傳 function
簡單來說,function 要能如一般變數與 object 一樣使用。
能將 function 以參數型式傳入 function
導致了 Higher Order Function 的觀念出現,如 Rx.js 一堆 operator,就是 Higher Order Function。
能在 function 回傳 function
則導致了 Pipeline、Compose 與 Currying 的觀念出現。
一般 OOP 語言都會某種程度的支援 FP,如 Higher Order Function 在 C#、JavaScript、PHP … 都可以實現。
但 Pipeline、Compose 與 Currying 在一般 OOP 語言則沒有,或者要另外安裝其他 package 才能實現,但這些觀念在 F# 都是原生支援。
User Story
我們想將陣列 1, 2, 3, 4, 5
的資料中,將所 奇數
平方再加 1
。
Task
根據 JavaScript、Linq 、Rx.js 的經驗,我們不再使用迴圈,而會使用 Higher Order Function 來解決問題。
Higher Order Function
Program.fs
open System [<EntryPoint>] let main argv = let numbers = [1; 2; 3; 4; 5] let isOdd x = x % 2 <> 0 let square x = x * x let addOne x = x + 1 let func values = let odds = List.filter isOdd values let squares = List.map square odds let result = List.map addOne squares result printfn "%A" (func numbers) 0
12 行
let odds = List.filter isOdd values
使用 List.filter
先找出所有 奇數
。
-
isOdd
: 傳入判斷奇數
的 function -
values
: 傳入欲處理資料 -
odds
: 回傳所有奇數
第 7 行
let isOdd x = x % 2 <> 0
定義 isOdd
,當 % 2
餘數不為 0
時為 奇數
。
在 F#,因為已經將 function 視為一般變數,所以無論是 value 或 function,都統一使用 let
13 行
let squares = List.map square odds
既然已經找出所有 奇數
,接下來就是使用 List.map
計算 平方
。
-
square
: 傳入計算平方
的 function -
odds
: 傳入所有奇數
-
squares
: 回傳所有平方
第 8 行
let square x = x * x
定義 square
,計算平方。
14 行
let result = List.map addOne squares
既然已經計算出所有 奇數的平方
,接下來就是使用 List.map
計算 +1
。
-
square
: 傳入計算+1
的 function -
odds
: 傳入所有奇數的平方
-
squares
: 回傳所有平方+1
第 9 行
let addOne x = x + 1
定義 addOne
,計算 +1
。
15 行
result
要回傳的變數, F# 不用寫 return
。
相對於 C-style 語言,我們發現 F# 有幾個特色
-
沒有
{}
,完全用縮排表示,類似 Python -
Function 傳入參數不需
()
,只需空白隔開即可 -
變數與 function 統一使用
let
-
回傳值不需要
return
這些只是語法的差異,只要習慣即可,不過平心而論,C-style 語言寫久,會發現 code 都一堆 ()
{}
與 return
都是贅字,F# 這種 coding style 乾淨很多
Pipeline 與 Currying
由於 List.filter
、 List.map
與 List.map
是依序處理,因此我們要不斷定義中繼變數 : odds
與 squares
傳入,事實上這些也是多餘的,若能省略則更好,這就是 Pipeline。
Program.fs
open System [<EntryPoint>] let main argv = let numbers = [1; 2; 3; 4; 5] let isOdd x = x % 2 <> 0 let square x = x * x let addOne x = x + 1 let func values = values |> List.filter isOdd |> List.map square |> List.map addOne printfn "%A" (func numbers) 0
12 行
values |> List.filter isOdd |> List.map square |> List.map addOne
|>
為 F# 的 Pipeline 符號,表示將 function 的 output 作為下一個 function 的 input。
因此我們可以透過 |>
表示先執行 List.flter
,然後再將結果傳入 List.map
,最後再將結果傳入 List.map
,這樣可以很清楚的表示流程,語意比 imperative 寫法更清楚。
Q : 可以明明 List.map
與 List.filter
是 2 個參數,第 1 個參數是 function,第 2 個參數是 value,但為什麼 value 都不用傳呢 ?
當 function 參數沒有傳完全時,F# 將回傳一個新的 function,新的 function 只要傳入剩下的參數即可,這稱為 Currying。
當 List.filter isOdd
只傳入 1 個參數時,由於參數沒有傳完整,將回傳一個新的 function,然後 |>
再將 values
傳入新的 function,如此 List.filter
才算完整,才能回傳 所有奇數
,最後再將 所有奇數
透過 |>
傳給下一個 List.map
,剩下以此類推。
Compose
Pipeline 雖然已經夠清楚,但 pipeline 基本上仍然是回傳 value,若我們能將所有 function 先組合好,最後統一透過一個 function 執行,那就更好了,這就是 Compose。
Program.fs
open System [<EntryPoint>] let main argv = let numbers = [1; 2; 3; 4; 5] let isOdd x = x % 2 <> 0 let square x = x * x let addOne x = x + 1 let sqaureAddOne = square >> addOne let func = List.filter isOdd >> List.map sqaureAddOne printfn "%A" (func numbers) 0
12 行
let func = List.filter isOdd >> List.map sqaureAddOne
>>
為 F# 的 compose 符號,專門負責組合 function。
因為連續兩個 List.map
,因此我們先將 square 與 addOne 組合成新的 sqaureAddOne
function,再交給 List.map
執行。
由於是先執行 List.fiter
,再執行 List.map
,因此使用 List.filter >> List.map
。
>>
不只代表 compose,也代表執行方向,所以也有 <<
。
Conclusion
- 本文簡單的展示 F# 最關鍵的 Pipeline、Currying 與 Compose,這些都是 OOP 語言很難見到的強悍功能,透過 F# 的簡單實作,讓我們在練習 FP 時更加方便
-
F# 並不是要取代 C#,事實上在 .NET Core,C# 仍是必學的語言,只是透過學習 F#,能訓練自己 FP 的思維,進而用在 C# 與 TypeScript 上
-
若語言間的 paradigm 相同,只是 syntax 不同,則沒有學習新語言的必要;但若透過更好的 syntax,讓你學到不同的 paradigm,這就有意義了,這就是學習 F# 的原因
Sample Code
完整的範例可以在我的 GitHub 上找到
Reference
F# , Tour of F#
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- WWDC2017四大系统更新汇总:惊喜多,还有中国特色
- MSF5一些特色以及如何使用其免杀
- 面向NLP场景应用的智能辅助建模(五)特色与优势
- 苹果或推出中国特色版iPhone 去Face ID配屏幕指纹
- 基于 Debian 以 Plasma 为特色的发行版 Neptune 发布 5.4 版
- Percona Server for MongoDB 4.0.10-5 发布,以 Hashicor Vault 集成为特色
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Lean Analytics
Alistair Croll、Benjamin Yoskovitz / O'Reilly Media / 2013-3-18 / USD 29.99
If you're involved with a startup, analytics help you find your way to the right product and market before the money runs out. But with a flood of information available, where do you start? This book ......一起来看看 《Lean Analytics》 这本书的介绍吧!