了解下F (2) 數值運算和流程控制語法

2021-12-29 22:39:03 字數 4075 閱讀 2507

那為什麼在2023年的現在,那麼多新的語言和技術,我們還要來了解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

四則運算和模運算(取餘)不必多說,但對於浮點數(float和float32)型別,還支援**(冪)語法。

2. ** 3.;; // val it : float = 8.0像abs、sin等這些基本數學函式在f#裡也包含在操作符(operators)的模組裡,所有操作符可在msdn文章(core.operators module(f#))檢視。

在上一篇的數值型別對比中,我們可以看出,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);; 當然也可以使用.net框架的system.convert靜態類。上述方法在轉換字串時也是呼叫的此方法。

f#中的位運算子均使用三重符號:

運算子 名稱 示例 結果 &&& 與 0b1111 &&& 0b0011 3 \ \ \ ~~~ 取反 ~~~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 介面)。

下面是0到100的迴圈,從0列印到100:

c# **:

for (int i=0; i<=100; 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到0f#版本中的[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)

f# **:

let mutable i = 0

while i <= 100 do

printfn "%i"

i 需要注意的是,f#中並沒有do...while的迴圈,在for迴圈和while迴圈中,也都沒有break和continue關鍵字。

剛開始接觸f#或習慣了c#的迴圈語句可能會不習慣,但當你熟悉了函式式程式設計的思想後,會發現這些在f#中都是不重要的,甚至迴圈語句都是不必要的

同時,也盡量不要使用可變型別。因為值的不可變性,使多執行緒程式設計變得簡單;而在c#中,因為值預設為可變的,使程式在多執行緒執行中增加了很多不確定因素。

在上面的示例**中已經使用過if語句。

在f#中,if語句的完整結構是這樣的:

if x>y then "x大於y"

elif xy then printfn "x大於y" //if分支無返回值在f#的if語句中,每個分支必須返回相同型別的值,但不需要return關鍵字(在介紹函式時會涉及)。

如果if分支沒有返回值(即返回unit),則else為可選的;否則,必須有else分支。(類似於c#的?:操作符,但f#中沒有這個操作符。)

c#中的else if在f#中為elif。

在c#中,還有一種分支結構的語句是使用switch...case。在f#中類似的語法是match...with。

c# **:

int i = 1;

switch (i)

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#特有的型別。

關於WebRTC,各種開源Codec和F22戰鬥機

webrtc很強大,出自gips的的名家之手的產品果然不同。以前qq,skype,cisco webex 等很多語音大型應用公司都是用這個引擎,在gips被google收購並開源之後,這些大廠反而因為失去維護而變得不知所措。紛紛自己組織人馬開發各自的引擎。這裡有兩個問題,乙個是付錢買產品與維護的問題...

關於WebRTC,各種開源Codec和F22戰鬥機

webrtc很強大,出自gips的的名家之手的產品果然不同。以前qq,skype,cisco webex 等很多語音大型應用公司都是用這個引擎,在gips被google收購並開源之後,這些大廠反而因為失去維護而變得不知所措。紛紛自己組織人馬開發各自的引擎。這裡有兩個問題,乙個是付錢買產品與維護的問題...

電腦開機,需按F2才能開機怎麼辦

大多數使用計算機的人都會遇到開機故障這一問題,電腦開機故障是很常見的問題之一。開機故障的問題各種各樣,不知道你是否遇到過電腦每次開機都要按f2才能繼續執行這一問題,這是是怎麼回事呢?依據我在u深度所看到一篇文章,總結分享給大家關於電腦開機的時候,需要 按f2才能繼續執行的處 理方法。按f2才能進入系...