本文鏈接:http://www.cnblogs.com/hjklin/p/fs-for-cs-dev-2.html
一些廢話
一門語言火不火,與語言本身並沒太大關系,主要看語言的推廣。
推廣得好,用的人多,問題也能及時得到解決,用的人就越多,這是一個良性循環,即使語言本身有很多不足也很快能得到解決。
但有的語言本身很好,使用者卻不多,缺少交流和推廣,致使進入惡性循環。
《黑客與畫家》作者把Lisp吹上天,但卻沒見他繼續推廣,至今在使用的團隊和行業還是很有限。
而說到F#,國內也出過F#的高校教材,不知道是否有高校開課,在企業上更是很少使用。
“趙姐夫”(博客)在10年說過要做F#在國內的推廣者,幾年過去了,也是無聲無息。
那為什么在2016年的現在,那么多新的語言和技術,我們還要來了解F#呢?
- F#和C#一樣,也是基於.Net平台的語言,了解了語法后,就能快速地使用.Net框架甚至C#編寫的框架,
而且在學習過程中.Net框架中很多以前不理解的東西,通過F#就變得很容易理解了。作為.Net程序員,還是值得了解的。 - 函數式語言的“天然支持異步和並行”的能力,也使得多線程開發變得簡單。
C#在最近的版本中經常得益於F#對.Net框架的推進,如加入了async
關鍵字,有Tuple
了(雖然在語法層面不支持)等等。 - 在最近發布的.Net Core中,也可以通過
dotnet new -l f#
來創建F#項目。.Net Core里F#的坑,這里就不細說了。 😅 通過.Net博客,也可以發現越來越多人在使用F#。
F#並無法替代C#,但兩者卻能起到互補的作用。
記得《七周七語言》里說過:
每學一門新的語言,思維方式都會發生改變。編程語言亦是如此。
作者在書中說,每學習一門語言都會去找互動教程,但大多數情況下並找不到稱心如意的。
若想領會一門語言的精髓,它(指互動教程)可就無能為力了。我想要的是那種痛快淋漓、深入探索語言本質的感覺。
我是沒有作者的這種能通過探索語言本質的能力來介紹F#,但希望也能讓大家發現F#語言的動人心弦之處。
廢話說得有點多了,下面繼續介紹F#吧。
數值運算
我們再翻出上一篇的小例子:
let mutable sum = 0
for i = 0 to 100 do
if i%2 <> 0 then sum <- sum + i
printfn "0到100中的奇數的和為%A" sum ;;
四則運算和模運算(取余)不必多說,但對於浮點數(float
和float32
)類型,還支持**
(冪)語法。
2. ** 3.;; // val it : float = 8.0
像abs
、sin
等這些基本數學函數在F#里也包含在操作符(Operators)的模塊里,所有操作符可在MSDN文章(Core.Operators Module(F#))查看。
大整數(BigInteger)
在上一篇的數值類型對比中,我們可以看出,F#在語法層面上支持大整數。
大整數於.Net 4.0添加到框架中,在System.Numerics
模塊里。F#創建項目時默認引用了此dll。(大整數也支持**
運算符,但指數必須為int
,其實就是Pow
方法。)
let bigInt = 4325I;; //相當於C#的 var bigInt = new BigInteger(4325);
3I ** 8;; // val it : System.Numerics.BigInteger = 6561 ...
在內存足夠的情況下,BigInteger
支持任意大的整數。 通過大整數,我們也可以自己實現大實數,或直接使用第三方類庫。
數值類型轉換
在F#中,沒有隱式類型轉換,就連int
到long
或float
也沒有。所以,數值類型轉換使用返回對應類型的轉換函數:
int 2.5;; // 2
float "3.1415" // 3.1415
(float 2)**(float 3);; //8.0
當然也可以使用.Net框架的System.Convert
靜態類。上述方法在轉換字符串時也是調用的此方法。
位運算符
F#中的位運算符均使用三重符號:
運算符 | 名稱 | 示例 | 結果 |
---|---|---|---|
&&& | 與 | 0b1111 &&& 0b0011 | 3 |
||| | 或 | 0xFF00 ||| 0x00FF | 65535 |
~~~ | 取反 | ~~~0b0011 | -4 |
^^^ | 異或 | 0b0011 ^^^ 0b0101 | 6 |
<<< | 左移 | 0b0001 <<< 3 | 8 |
>>> | 右移 | 0b1000 >>> 3 | 1 |
注:“或”使用|||
,博客園的Markdown渲染時,竟然不支持表格里的|
轉義。😅
比較
因為函數式語言中,數值不可變,所以=
在F#中並不是賦值符號。
=
在F#執行相等比較操作,而不等則為<>
,這兩個符號與C#有異:
5=8 ;; //false
"ax"<>"ay" ;; //true
那就會有人說,F#也有可變的值啊,怎么賦值呢!沒錯,在上面的示例代碼中sum
為可變值,每次循環通過<-
符號改變其值。好詭異但又好有道理的符號啊! 😲
所以需要注意,C#中的 int i = 1;
其實是相當於F#中的 let mutable i = 1
。因為C#默認創建的是可變類型。 請查看后面的while循環介紹。
此外,F#中還有一個compare
函數用來比較兩個值:
compare 31 31;; // 0
compare 5 4;; // 1
(*
compare x y
若x > y則返回1;若x < y則返回-1;若x = y則返回0
*)
這個比較在C#中有實現過IComparable
接口的應該了解,其實compare
函數的參數就是需要實現了IComparable
接口的類型。
在.Net中,比較是一個復雜的話題,在此就不展開了,可參考MSDN文章(Object.Equals方法和IComparable 接口)。
流程控制語法
for循環語句
下面是0到100的循環,從0打印到100:
- C# 代碼:
for (int i=0; i<=100; i++) { System.Console.WriteLine(i); }
- F# 代碼:
for i=0 to 100 do printfn "%i" i
for i in [0..100] do printfn "%i" i
for i=100 downto 0 do printfn "%i" i //逆向循環,從100到0
F#版本中的[0..100]
是創建一個從0到100的列表(list
),在之后列表模塊會進行介紹。
遺憾的是for ... to
和for ... downto
語句無法創建如for (int i=0; i<=100; i+=2)
這種間隔不為1的循環,只能使用for ... in
再加上一個列表。
while循環語句
用while
循環實現的從0打印到100:
- C# 代碼:
int i = 0;
while (i <= 100)
{
System.Console.WriteLine(i);
i++;
}
- F# 代碼:
let mutable i = 0
while i <= 100 do
printfn "%i"
i <- i + 1
需要注意的是,F#中並沒有do...while
的循環,在for
循環和while
循環中,也都沒有break
和continue
關鍵字。
剛開始接觸F#或習慣了C#的循環語句可能會不習慣,但當你熟悉了函數式編程的思想后,會發現這些在F#中都是不重要的,甚至循環語句都是不必要的。
同時,也盡量不要使用可變類型。因為值的不可變性,使多線程編程變得簡單;而在C#中,因為值默認為可變的,使程序在多線程運行中增加了很多不確定因素。
條件語句之if
在上面的示例代碼中已經使用過if
語句。
在F#中,if
語句的完整結構是這樣的:
if x>y then "x大於y"
elif x<y then "x小於y"
else "x等於y"
if x>y then printfn "x大於y" //if分支無返回值
在F#的if語句中,每個分支必須返回相同類型的值,但不需要return
關鍵字(在介紹函數時會涉及)。
如果if分支沒有返回值(即返回unit
),則else為可選的;否則,必須有else分支。(類似於C#的?:
操作符,但F#中沒有這個操作符。)
C#中的else if
在F#中為elif
。
條件語句之switch(match)
在C#中,還有一種分支結構的語句是使用switch...case
。在F#中類似的語法是match...with
。
- C# 代碼:
int i = 1;
switch (i)
{
case 1:
Console.WriteLine("this is one");
break;
case 2:
Console.WriteLine("this is two");
break;
case 3:
Console.WriteLine("this is three");
break;
default:
Console.WriteLine("this is something else");
break;
}
- F# 代碼:
let i = 1
match i with
| 1 -> printfn "this is one"
| 2 -> printfn "this is two"
| 3 -> printfn "this is three"
| _ -> printfn "this is anything else"
其中_
為通配符,與C#switch
中的default
類似。
但F#中的match
語句功能非常強大,可查看MSDN文章Match表達式(Match Expressions)和
模式匹配(Pattern Matching)。
模式匹配在函數式編程中有着作用,在之后的函數式編程中也會進行介紹。
在下一篇中,我們來了解數組和列表,以及一些F#特有的類型。