如果你也會C#,那不妨了解下F#(2):數值運算和流程控制語法


本文鏈接: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 ;;

四則運算和模運算(取余)不必多說,但對於浮點數(floatfloat32)類型,還支持**(冪)語法。

2. ** 3.;;  // val it : float = 8.0

abssin等這些基本數學函數在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#中,沒有隱式類型轉換,就連intlongfloat也沒有。所以,數值類型轉換使用返回對應類型的轉換函數:

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 ... tofor ... 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循環中,也都沒有breakcontinue關鍵字。
剛開始接觸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#特有的類型。


免責聲明!

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



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