




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
1、.NET Framework 中的函數(shù)式編程技術(shù) 懶人ABC發(fā)表于2020-09-07 00:20原文鏈接閱讀:2評論:2 F#入門使用.NET Framework中的函數(shù)式編程技術(shù)Ted Neward本文討論:安裝F#F#語言根底.NET互操作性異步F#本文使用了以下技術(shù):.NET Framework,F#目錄為什么要使用F#?安裝F#您好,F(xiàn)#Let表達式關(guān)鍵字For管道F#也可以處理對象異步F#與F#合作作為Microsoft.NET Framework家族的新成員,F(xiàn)#提供類型平安、性能以及類似腳本語言的工作才能,所有這些都是.NET環(huán)境的一部分。此函數(shù)式語言由Microsoft研究院
2、的Don Syme創(chuàng)造,作為CLR的OCaml語法兼容變體,但F#已經(jīng)迅速地從科研轉(zhuǎn)為投入實際應(yīng)用。隨著函數(shù)式編程的概念通過.NET泛型和LINQ等技術(shù)越來越多地滲入主流語言例如C#和Visual Basic,F(xiàn)#在.NET社區(qū)里的知名程度也不斷進步-因此,2007年11月Microsoft宣布將F#確定為受支持的.NET編程語言。多年來,大家一直認(rèn)為函數(shù)式語言領(lǐng)域ML、Haskell等更適宜用于學(xué)術(shù)研究,而不適用于專業(yè)開發(fā)。但這并不代表這些語言沒有過人之處。事實上,.NET的一些重要的功能增強例如泛型、LINQ、PLINQ和Futures都是將一些函數(shù)式編程概念全新應(yīng)用到語言所致。以往對這些
3、語言的關(guān)注程度不高主要是因為它們的目的平臺與專為Windows編寫程序的開發(fā)人員關(guān)系不大、不能與底層平臺很好集成,或者不支持關(guān)系數(shù)據(jù)庫訪問、XML解析和進程外通信機制等主要功能。但是,CLR及其"多種語言,單一平臺"的方法將使此類語言在Windows開發(fā)中的應(yīng)用越來越廣泛。并且順理成章地引起在一線工作的程序員們的注意。F#即是這樣一門語言。在本文中,我將為您介紹一些F#的根本概念和優(yōu)點。然后,為了幫助您初步理解F#,我將詳細(xì)介紹它的安裝過程并編寫幾個簡單的小程序。為什么要使用F#?對于小部分.NET程序員來說,學(xué)習(xí)一門.NET Framework函數(shù)化語言無疑將使自己在編寫
4、功能強大軟件方面前進一大步。而對其他程序員來說,學(xué)習(xí)F#的理由就因人而異了。F#能為開發(fā)人員提供哪些好處?隨著多核CPU的普及,平安并發(fā)程序已成為過去三年來的關(guān)注焦點。函數(shù)式語言倡導(dǎo)一種固定不變的數(shù)據(jù)構(gòu)造,可在線程和機器之間傳遞,而無需擔(dān)憂線程平安或原子訪問,開發(fā)人員可以利用這一特點支持并發(fā)操作。函數(shù)式語言還可更輕松地編寫更支持并發(fā)特性的庫,如稍后將在本文中介紹的F#異步工作流。盡管對于專攻面向?qū)ο箝_發(fā)的程序員而言,可能對這種語言感覺不是這么強烈,但在很多情況下,函數(shù)式程序確實可以簡化某些應(yīng)用程序的編寫和維護。例如,編寫一個將XML文檔轉(zhuǎn)換成其他格式數(shù)據(jù)的程序。雖然完全可以通過編寫一個C#程序
5、,讓它解析整個XML文檔并應(yīng)用各種if語句確定在文檔中的不同位置采取何種措施,但實際上更好的方法是編寫可擴展款式表語言轉(zhuǎn)換XSLT程序。當(dāng)然,XSLT肯定包含大量的內(nèi)置函數(shù)機制,如同SQL一樣。F#強烈建議不要使用空值null,而是提倡使用固定不變的數(shù)據(jù)構(gòu)造。這些特性可以減少需要編寫的特例代碼量,從而有助于降低編程出錯的頻率。使用F#編寫的程序還更加簡潔。您可以實在地從兩方面減少鍵入的內(nèi)容:擊鍵次數(shù)更少并且必需要向編譯器通告變量類型、參數(shù)或返回類型的位置點也更少。這意味著需要維護的代碼將大大減少。F#具有與C#相似的性能特點。但是,與簡潔程度相似的語言特別是那些動態(tài)和腳本語言相比,它的性能特點
6、要好得多。并且,F(xiàn)#也包含通過編寫程序段并交互式執(zhí)行查看數(shù)據(jù)的工具,這一點與許多動態(tài)語言類似。安裝F#F#可從research.microsoft /fsharp/fsharp.aspx免費下載,它不僅會安裝所有命令行工具,而且還會安裝Visual Studio擴展軟件包,該軟件包提供彩色語法突出顯示、工程和文件模板包括作為入門指南的詳細(xì)F#例如代碼以及IntelliSense支持。同時它還提供可在Visual Studio內(nèi)部運行的F#交互式shell,它使開發(fā)人員可以從源文件窗口中提取表達式、將表達式粘貼到交互式shell窗口,并立即得到代碼段的結(jié)果-在類似增強的Immediate窗口中顯
7、示結(jié)果。在我撰寫本專欄時,F(xiàn)#在Visual Studio內(nèi)作為外部工具運行,所以它缺少某些開發(fā)人員可以從C#或Visual Basic中獲得的無縫集成的才能。此外,F(xiàn)#還缺少ASP.NET頁面設(shè)計器支持。這并不是說F#不能在ASP.NET中使用,完全不是。這僅表示Visual Studio并沒有為F#提供類似C#和Visual Basic的那種現(xiàn)成拖放式開發(fā)體驗。盡管如此,當(dāng)前版本的F#還是可以在可以使用其他.NET兼容語言的任何位置使用。在接下來的幾頁中,您將看到一些例如。您好,F(xiàn)#介紹任何語言的特有方式就是通過那幾乎成為標(biāo)準(zhǔn)的"Hello,World"程序。F#也不例
8、外:復(fù)制代碼printf"Hello,world!"雖然不能引起您太大的興趣,但這個很小的例子顯示出F#屬于不需要顯式入口點C#、Visual Basic和C+/CLI都需要顯式入口點的語言;該語言假設(shè)程序的第一行即為入口點并將從此處開場執(zhí)行。要運行此程序,剛?cè)腴T的F#開發(fā)人員有兩個選擇:編譯或解釋。在F#解釋程序中運行此程序fsi.exe很簡單。只需從命令行啟動fsi.exe并在出現(xiàn)的提示中輸入上面一行內(nèi)容即可,如圖1所示。圖1在F#解釋程序中運行'Hello,World'單擊該圖像獲得較大視圖請注意,在shell中,每條語句必須以兩個分號結(jié)尾。這是交互形
9、式的特殊要求,編譯過的F#程序并不需要使用這種方式。要將此例如作為標(biāo)準(zhǔn)的.NET可執(zhí)行程序運行,請正常啟動Visual Studio并創(chuàng)立一個新的F#工程可以在"其他工程類型"中找到這個工程。最初,F(xiàn)#工程包含一個F#源文件,稱為file1.fs。翻開此文件將發(fā)現(xiàn)大量例如F#代碼集合。閱讀一下這些內(nèi)容即可大概理解F#的語法構(gòu)造。然后將整個文件交換成前面所顯示的"Hello,world!"代碼。運行此應(yīng)用程序,毫無疑問,在控制臺應(yīng)用程序窗口中將出現(xiàn)"Hello,world!"。假設(shè)更喜歡命令行方式,可以使用F#安裝目錄中bin子目錄里的
10、fsc.exe工具編譯這段代碼。請注意:fsc.exe與大多數(shù)命令行編譯器的工作方式相似,它從命令行獲取源代碼并生成可執(zhí)行程序作為結(jié)果。大多數(shù)命令行開關(guān)都有相關(guān)文檔,假設(shè)曾經(jīng)使用過csc.exe或cl.exe編譯器,那您可能已經(jīng)熟悉其中許多開關(guān)。不過請注意,F(xiàn)#目前對MSBuild的支持尚不完美;在當(dāng)前安裝版本撰寫本文時為中不能直接支持由MSBuild驅(qū)動的編譯。假設(shè)希望"Hello,world!"中更具圖形化特點,F(xiàn)#可以通過CLR平臺包括Windows Forms庫輕松地提供完好的逼真度和互操作性。嘗試以下代碼:復(fù)制代碼System.Windows.For
11、ms.MessageBox.Show"Hello World"利用.NET Framework類庫和F#庫的才能使得F#語言不僅對那些早已使用如OCaml或Haskell之類函數(shù)式語言進展數(shù)學(xué)和科學(xué)計算的社區(qū)極具吸引力,而且受到全世界現(xiàn)有.NET開發(fā)人員的青睞。Let表達式讓我們看看比傳統(tǒng)"Hello,world!"更復(fù)雜一些的F#代碼例如。請看以下代碼:復(fù)制代碼let results=for iin 0.100-i,i*iprintfn"results=%A"results在該F#語法中,let表達式是令人產(chǎn)生好奇的元素。它是整個語
12、言中最重要的表達式。更正式地說,let可以為標(biāo)識符賦值。用Visual Basic和C#開發(fā)人員的行話來說,"它可以定義一個變量"。但這并不確切。在F#中,標(biāo)識符包含兩個要素。首先,標(biāo)識符一旦定義就不能再更改。這即是F#幫助程序員創(chuàng)立并發(fā)平安程序的方法,因為它不提倡可變的狀態(tài)。第二,標(biāo)識符不僅可以是基元類型或?qū)ο箢愋腿鏑#和Visual Basic中所使用的類型,而且還可以是函數(shù)類型,這一點與LINQ相似。同時還請注意,標(biāo)識符從不顯式定義為類型。例如,從不定義結(jié)果標(biāo)識符;它將從后面表達式的右側(cè)進展推斷。這稱為類型推斷,并且它代表編譯器分析代碼、確定返回值和自動插入返回值的才
13、能這與新的C#推斷類型表達式通過變量關(guān)鍵字進展推斷的方法類似。Let表達式不僅可以處理數(shù)據(jù),還可以使用它來定義函數(shù),F(xiàn)#將函數(shù)看作第一級概念。下面的例如定義了一個加法函數(shù),它使用兩個參數(shù)a和b:復(fù)制代碼let add ab=a+b完全按照您預(yù)期的方式工作:將a與b相加,并將結(jié)果顯式返回給調(diào)用者。這意味著從技術(shù)上講,F(xiàn)#中的每個函數(shù)都將返回一個值,即使返回的不一定是值,也會返回一個特殊的名稱unit。這將在F#代碼中產(chǎn)生一些有趣的暗示,特別是與.NET Framework類庫相交的部分。但目前,C#和Visual Basic開發(fā)人員可以把unit大致看作是與void一樣的類型。有時函數(shù)應(yīng)該忽略傳
14、遞給它的參數(shù)。要在F#中達此目的,僅需使用下劃線作為該參數(shù)的占位符即可:復(fù)制代碼let return10 _=add 55/12 is effectively ignored,and ten is set to the resulting/value of add 55 let ten=return10 12 printf"ten=%dn"ten與許多函數(shù)式語言類似,F(xiàn)#允許根據(jù)其調(diào)用進展currying可以僅部分定義函數(shù)的應(yīng)用,以便提供其余的參數(shù):復(fù)制代碼let add5 a=add a5在某種程度上,這與創(chuàng)立一個承受不同的參數(shù)集并調(diào)用其他方法的重載方法相似:復(fù)制代碼pu
15、blic class Adderspublic static int addint a,int breturn a+b;public static int add5int areturn adda,5;但兩者還是有一點細(xì)微的差異。請注意,在F#版本中,沒有顯式定義類型。這表示編譯器將采用自己的類型推斷方法確定add5的參數(shù)是否是與加上整數(shù)5兼容的類型,并確定是按照這種方式編譯,還是將其標(biāo)記為錯誤。事實上,F(xiàn)#語言主要使用隱式類型參數(shù)化即使用泛型。在Visual Studio中,將指針停放在前面所顯示的ten的定義上時,將說明其類型聲明為:復(fù)制代碼val ten:'a-int在F#中,這
16、表示ten是一個值,一個獲取任意類型的參數(shù)并產(chǎn)生整數(shù)結(jié)果的函數(shù)。這種記號語法大致等同于C#中的T語法,所以對C#函數(shù)最貼切的說法是:ten是類型參數(shù)化方法的委托實例,您想要忽略其類型但在C#規(guī)那么下不可忽略:復(fù)制代碼delegate int Transformer TT ignored;public class Apppublic static int return10object ignoredreturn 5+5;static void MainTransformer object ten=return10;System.Console.WriteLine"ten=0"
17、,return100;關(guān)鍵字For如今讓我們看一下第一個例如中的for關(guān)鍵字:復(fù)制代碼#light let results=for iin 0.100-i,i*iprintfn"results=%A"results先看代碼的頂部,注意#light語法。這是為非OCaml程序員開場使用F#而做的讓步,放寬某些OCaml語言的語法要求,并使用大量空白定義代碼塊。雖然不一定必要,但對于那些本來使用C#或Visual Basic的普通開發(fā)人員來說,它確實使語法更易于解析,因此它常出如今F#例如和公開的代碼段中,并已成為事實上的F#編程標(biāo)準(zhǔn)。將來版本的F#可能會將#light確定為默
18、認(rèn)語法,代替其他類似方法。那個看似簡單的for循環(huán)實際上并不簡單。正式地說,這是生成列表,即將生成列表型結(jié)果的代碼塊的另一種說法。列表是函數(shù)式語言中經(jīng)常出現(xiàn)的一種原語構(gòu)造,在這方面它與數(shù)組有許多相似之處。但是,列表不允許基于位置的訪問如C#中傳統(tǒng)的ai語法。列表可在函數(shù)式編程的不同位置出現(xiàn),大多數(shù)情況中,可以將其看作是F#中與.NET Framework中的List T類似,但提供一些增強功能的同等項。列表通常使用一些特殊類型,本例中標(biāo)識符結(jié)果是聚合列表,特別地是F#將此聚合類型標(biāo)識為類型int*int。假設(shè)將此聚合列表看作是SQL中SELECT語句返回的一對列,它的含義就清楚多了。因此,例如
19、本質(zhì)上是創(chuàng)立一個包含100個工程的整數(shù)對列表。通常,在函數(shù)式語言中,函數(shù)定義可以在出現(xiàn)代碼的任何位置使用。因此,假設(shè)希望擴展前面的例如,可以編寫以下代碼:復(fù)制代碼let compute2 x=x,x*xlet compute3 x=x,x*x,x*x*xlet results2=for iin 0.100-compute2 ilet results3=for iin 0.100-compute3 i遍歷列表或數(shù)組或其他一些重復(fù)構(gòu)造是函數(shù)式語言中很常見的任務(wù),它已成為根本方法調(diào)用:List.iter。它僅簡單地對列表中的每個元素調(diào)用一個函數(shù)。其他類似的庫函數(shù)還可提供一些非常有用的功能。例如,Li
20、st.map將函數(shù)作為參數(shù),并將該函數(shù)應(yīng)用于列表中的每個元素,并返回該過程產(chǎn)生的新列表。管道讓我們討論F#中另一個構(gòu)造-管道操作符,它通過類似命令shell如Windows PowerShell管道的通道獲取函數(shù)的結(jié)果,并將結(jié)果用作后一個函數(shù)的輸入。我們來看圖2中顯示的F#代碼段。該代碼段使用System.Net命名空間連接 效勞器,獲取相應(yīng)的HTML并分析結(jié)果。Figure 2檢索和分析HTML復(fù)制代碼/Get the contents of the URL via aweb request let url:string=let req=System.Net.WebRequest.Creat
21、eurllet resp=req.GetResponselet stream=resp.GetResponseStreamlet reader=new System.IO.StreamReaderstreamlet html=reader.ReadToEndresp.Closehtml let getWords s=String.split'';'n';'t';'';'';'='s let getStats site=let url="+site let html= url let wor
22、ds=html|getWords let hrefs=html|getWords|List.filterfun s-s="href"site,html.Length,words.Length,hrefs.Length請注意getStats定義中的words標(biāo)識符。它獲取從URL返回的html值,并對其應(yīng)用getWords函數(shù)。我還可以編寫定義讀?。簭?fù)制代碼let words=getWords html兩者等同。但是hrefs標(biāo)識符顯示了管道操作符的威力,通過管道操作符可以將任意多個應(yīng)用程序連接起來。此處我獲取words的結(jié)果列表,并將其通過管道傳遞給List.filter函
23、數(shù),該函數(shù)使用匿名函數(shù)查找單詞href,并在表達式為true時將其返回。并且,最重要的是,getStats調(diào)用的結(jié)果將是另一個聚合string*int*int*int。要使用C#編寫,需要的遠(yuǎn)遠(yuǎn)不止15行代碼。圖2中的例如還顯示出更多F#與.NET Framework的兼容性,以下代碼也表現(xiàn)出這一特性:復(fù)制代碼open System.Collections.Generic let capitals=Dictionary string,stringcapitals."Great Britain"-"London"capitals."France&
24、quot;-"Paris"capitals.ContainsKey"France"確實,這個例如除了練習(xí)Dictionary K,V類型外沒有什么其他內(nèi)容,但它顯示出在F#中如何指定泛型使用與C#一樣的尖括號、如何在F#中使用索引同樣與C#一樣使用方括號,以及如何執(zhí)行.NET方法使用與C#中同樣的點和圓括號。事實上,這里僅有的新內(nèi)容是使用左箭頭操作符為可變值賦值。這一點是必需的,因為F#與大多數(shù)函數(shù)式語言一樣,保存等號用于比較,以便保持?jǐn)?shù)學(xué)符號含義:假設(shè)x=y,那么x與y的值相等,而不是將y的值賦給x。真正的數(shù)學(xué)家們早已對普遍存在或設(shè)想過的x=x+1提出
25、異議,甚至偷笑不已。F#也可以處理對象當(dāng)然,并不是所有開場使用.NET的開發(fā)人員都愿意立即承受函數(shù)式的概念。事實上,大多數(shù)從C#或Visual Basic轉(zhuǎn)向F#的開發(fā)人員都需要知道他們在使用這一新語言時可以保存原有的習(xí)慣。在某種程度上,這是完全可行的。例如,請看圖3頂部所示的二維向量的類定義。其中就有一些有趣的概念。首先,請注意其中沒有顯式構(gòu)造函數(shù)體;第一行中的參數(shù)說明用于構(gòu)造Vector2D實例的參數(shù)本質(zhì)上就是構(gòu)造函數(shù)。因此長度標(biāo)識符,以及dx和dy標(biāo)識符將成為Vector2D類型的私有元素,而member關(guān)鍵字那么說明可以通過標(biāo)準(zhǔn).NET屬性訪問獲取的Vector2D外部可用成員。本質(zhì)上
26、,這段F#代碼聲明了您可在圖3底部看到的內(nèi)容由Reflector報告。Figure 3F#和C#中的矢量變體復(fù)制代碼VECTOR2D IN F#type Vector2Ddx:float,dy:float=let length=sqrtdx*dx+dy*dymember obj.Length=length member obj.DX=dx member obj.DY=dy member obj.Movedx2,dy2=Vector2Ddx+dx2,dy+dy2VECTOR2D IN C#REFLECTORSerializable,CompilationMappingSourceLevelCon
27、struct.ObjectTypepublic class Vector2D/Fields internal double _dx48;internal double _dy48;internal double _length49;/Methods public Vector2Ddouble dx,double dyHello.Vector2Dthis=this;this._dx48=dx;this._dy48=dy;double d=this._dx48*this._dx48+this._dy48*this._dy48;this._length49=Math.Sqrtd;public Hel
28、lo.Vector2D Movedouble dx2,double dy2return new Hello.Vector2Dthis._dx48+dx2,this._dy48+dy2;/Properties public double DXgetreturn this._dx48;public double DYgetreturn this._dy48;public double Lengthgetreturn this._length49;請記住,F(xiàn)#與大多數(shù)函數(shù)式語言相似,提倡使用不變的值和狀態(tài)。當(dāng)查看圖3中的代碼時,這一點尤為明顯,因為所有屬性都為只讀屬性,并且Move成員不會修改現(xiàn)有的
29、Vector2D,而是從當(dāng)前Vector2D創(chuàng)立新的副本,并在返回副本之前對其應(yīng)用修改的值。還請注意,F(xiàn)#版本不僅具備整體線程平安性,而且完全可以通過傳統(tǒng)的C#或Visual Basic代碼進展訪問。這為F#入門提供了一種簡便方法:使用它定義想要或者需要線程平安和固定不變的業(yè)務(wù)對象或其他類型。雖然完全可以在F#中創(chuàng)立提供常用可變操作組設(shè)置屬性及類似操作的類型,但需要更多的工作,而且需要使用mutable關(guān)鍵字才可完成。在當(dāng)今并發(fā)問題成為日常工作主旋律的世界中,這正如許多人所要求的一樣-默認(rèn)固定不變,必需或想要時可變。在F#中創(chuàng)立類型很有趣,但還是可以用F#去做那些傳統(tǒng)C#或Visual Bas
30、ic代碼可以做到的工作,如創(chuàng)立簡單的Windows窗體應(yīng)用程序并從用戶處搜集輸入,如圖4所示。Figure 4使用F#編寫Windows窗體復(fù)制代碼#light open System open System.IO open System.Windows.Forms open Printf let form=new FormText="My First F#Form",Visible=truelet menu=form.Menu-new MainMenulet mnuFile=form.Menu.MenuItems.Add"&File"let f
31、ilter="txt files*.txt|*.txt|All files*.*|*.*"let mnuiOpen=new MenuItem"&Open.",new EventHandlerfun _-let dialog=new OpenFileDialogInitialDirectory="c:",Filter=filter;FilterIndex=2,RestoreDirectory=trueif dialog.ShowDialog=DialogResult.OK then match dialog.OpenFilewi
32、th|null-printf"Could not read the file.n"|s-let r=new StreamReadersprintf"First line is:%s!n"r.ReadLine;s.Close;,Shortcut.CtrlOmnuFile.MenuItems.AddmnuiOpenSTAThreaddo Application.Runform任何熟悉Windows窗體的開發(fā)人員都可以立即明白這些代碼的含義:創(chuàng)立一個簡單的窗體、填充一些屬性、填入一個事件處理程序,并告訴應(yīng)用程序開場運行,直到用戶單擊右上角的"關(guān)閉&q
33、uot;按鈕。由于標(biāo)準(zhǔn)元素與.NET應(yīng)用程序一樣,所以只需重點關(guān)注F#語法即可。Open語句的操作與C#中using語句的作用大致一樣,本質(zhì)上都是翻開.NET命名空間以便在沒有正式限制符的情況下使用。Printf命名空間是F#原有的、技術(shù)上與OCaml模塊具有一樣名稱的端口。F#不僅具備完好的.NET Framework類庫,而且還有最簡潔的OCaml庫端口,這使得熟悉該語言的程序員可以象使用.NET Framework一樣對其運用自如。致好奇心強的程序員:Printf位于FSharp.Core.dll程序集中。您完全可以根據(jù)個人偏好隨時使用System.Console.WriteLine。窗
34、體標(biāo)識符的創(chuàng)立利用了F#命名參數(shù),它等同于實例化對象,然后調(diào)用一系列屬性集來為這些屬性填充值。我在下面的幾行中使用一樣的方法創(chuàng)立對話框標(biāo)識符。mnuiOpen標(biāo)識符的定義包含令人感興趣的構(gòu)造,該構(gòu)造對于熟悉.NET Framework 2.0匿名委托或.NET Framework 3.5中l(wèi)ambda表達式的開發(fā)人員來說并不陌生。構(gòu)造與Open MenuItem關(guān)聯(lián)的EventHandler時,您可以看到使用以下語法定義的匿名函數(shù):復(fù)制代碼fun _-.類似于匿名委托,這段代碼創(chuàng)立了一個將會在選中菜單項時調(diào)用的函數(shù),但語法略有技巧性。MenuItem定義中對EventHandler的定義是忽略
35、傳遞給它的兩個參數(shù)的匿名函數(shù),這兩個參數(shù)巧妙地對應(yīng)標(biāo)準(zhǔn)EventHandler委托類型中的發(fā)送方和事件參數(shù)。該函數(shù)規(guī)定顯示新的OpenFileDialog并在單擊"確定"時檢查結(jié)果.如下所示:復(fù)制代碼if dialog.ShowDialog=DialogResult.OK then match dialog.OpenFilewith|null-printf"Could not read the file.n"|s-let r=new StreamReadersin printf"First line is:%s!n"r.ReadLin
36、e;s.Close;將使用形式匹配檢查結(jié)果,該方法是函數(shù)化語言世界中一項強大的功能。形式匹配外表上與C#中的switch/case在某些地方存在相似之處,但實際上它名副其實地完成形式匹配工作:它將值與各種不同的形式進展比較這些形式不需要都是常量值,并執(zhí)行匹配的代碼塊。因此,以此處所示的匹配塊為例,OpenFile的結(jié)果可以匹配兩種可能的值:null表示無法翻開任何文件,或者分配任何非null值的s,該值將隨后用作StreamReader的構(gòu)造函數(shù)來翻開并讀取給定文本文件的第一行。形式匹配是大多數(shù)函數(shù)式語言的重要部分,對它做些研究是完全值得的。它的一個最常見的用處是與可辨識結(jié)合discrimin
37、ated union類型C#或Visual Basic中枚舉類型的不確切說法配合使用:復(fù)制代碼/Declaration of the'Expr'type type Expr=|Binary of string*Expr*Expr|Variable of string|Constant of int/Create avalue'v'representing'x+10'let v=Binary"+",Variable"x",Constant 10函數(shù)式語言中常用它來創(chuàng)立域特定語言的核心表示,開發(fā)人員可以使用它來
38、編寫更為復(fù)雜和強大的構(gòu)造。例如,不難想象擴展此語法以創(chuàng)立完全計算式語言,并可簡單地通過為Expr類型添加新元素而進一步擴展該語言。這里需要注意的是:使用*字符的語法并不表示使用乘法,它是函數(shù)式語言中用于指示某類型中包含多個部分的標(biāo)準(zhǔn)方式。事實上,函數(shù)式語言已經(jīng)非常普遍地應(yīng)用于編寫面向語言的編程工具如解釋器和編譯器,并且Expr類型最終將成為語言表達式類型的完好集合。F#通過其內(nèi)置的兩個工具:fslex和fsyacc專為獲得傳統(tǒng)語言輸入-lex和yacc文件-并將其編譯成F#代碼以便簡化操作而設(shè)計使這一切變得更為簡單。假設(shè)對此感興趣,可以下載F#安裝程序深化研究;特別是標(biāo)準(zhǔn)F#發(fā)行包中的Pars
39、ing例如將提供非常好的入門根底構(gòu)造??杀孀R結(jié)合只是形式匹配的優(yōu)勢之一,另一項優(yōu)勢是表達式的執(zhí)行,如圖5所示。位于eval定義中的rec是必需的,它告訴F#編譯器在定義主體內(nèi)迭代調(diào)用eval。假設(shè)沒有它,F(xiàn)#將期望出現(xiàn)一個名為eval的本地嵌套函數(shù)。實際使用時,我使用函數(shù)getVarValue為變量返回一些預(yù)定義的值,getVarValue將檢查Dictionary,查找變量創(chuàng)立時確定的返回值。Figure 5表達式執(zhí)行復(fù)制代碼let getVarValue v=match vwith|"x"-25|"y"-12|_-0 let rec eval x=m
40、atch xwith|Binaryop,l,r-letlv,rv=eval l,eval rin ifop="+"then lv+rv elifop="-"then lv-rv else failwith"E_UNSUPPORTED"|Variablevar-getVarValue var|Constantn-n do printf"Results=%dn"eval v當(dāng)調(diào)用eval時,它將得到值v并發(fā)現(xiàn)該值是一個Binary值。這與第一個子表達式匹配,該表達式隨后把值lv,rv綁定到剛檢查的Binary值左右兩側(cè)
41、的計算結(jié)果。未命名的值lv,rv是一個聚合本質(zhì)上是代表多個部分的單個值,這一點與關(guān)系集或C構(gòu)造相似。當(dāng)首次調(diào)用eval l時,來自Binary實例的l恰好是Variable類型,因此對eval的遞歸調(diào)用匹配該形式匹配塊的分支。隨后將調(diào)用getVarValue,它會返回硬編碼25,該值最終將綁定到值lv。對于包含值10的常量r來說順序一樣,因此它將綁定到rv。然后執(zhí)行代碼塊的剩余部分if/else-if/else塊,熟悉C#、Visual Basic或C+的開發(fā)人員可以很容易地讀懂該代碼塊的含義。這里需要再次強調(diào)的是:每個表達式都將返回一個值,甚至在形式匹配塊內(nèi)部也一樣。在本例中,返回值是一個整
42、型值,該值可能是運算得到的值、從變量中檢索到的值或者是常量本身。這一點似乎更容易讓習(xí)慣于面向?qū)ο蠡蜻^程化編程的開發(fā)人員產(chǎn)生微詞,因為在C#、Visual Basic或C+中,返回值是可選的,并且甚至在指定返回值的情況下仍可以忽略返回值。在類似F#的函數(shù)式語言中,要忽略返回值需要顯式編碼表達方式。假設(shè)出現(xiàn)這種情況,程序員可以將結(jié)果傳給名為ignore的函數(shù),由它完成適當(dāng)?shù)牟僮?。異步F#目前為止,我對F#語法的介紹采用以下兩種方式中的一種:或者使用相對簡單的函數(shù)式構(gòu)造,或者使其看起來比較初級且簡潔,象是傳統(tǒng)面向?qū)ο蟆?NET兼容語言C#、Visual Basic或C+/CLI的變體。這種介紹很難推
43、動在企業(yè)內(nèi)采用F#。但是請看一以以下圖6。它可與前面兩種形式截然不同。除了多處出現(xiàn)!字符并使用async修飾符外,這是一段看起來相比照較直觀的代碼:加載源圖像映像、提取其數(shù)據(jù)、將數(shù)據(jù)傳遞到獨立的函數(shù)進展加工旋轉(zhuǎn)、拉伸或其他操作,并將數(shù)據(jù)寫回輸出文件。Figure 6處理圖像復(fù)制代碼let TransformImage pixels i=/Some kind of graphic manipulation of images let ProcessImagei=asyncuse inStream=File.OpenReadsprintf"source%d.jpg"ilet!p
44、ixels=inStream.ReadAsync1024*1024let pixels'=TransformImagepixels,iuse outStream=File.OpenWritesprintf"result%d.jpg"ido!outStream.WriteAsyncpixels'do Console.WriteLine"done!"let ProcessImages=Async.RunAsync.Parallelfor iin 1.numImages-ProcessImagei較不明顯的是使用async修飾符使這段代碼進入F
45、#所稱的異步工作流與Windows Workflow Foundation無關(guān)中,這意味著這些加載/處理/保存步驟的每一步都在.NET線程池的平行線程中執(zhí)行。為了使其更簡單,看一以以下圖7中的代碼。這種特殊的順序以相對簡單且易于理解的方式顯示出異步工作流。不用深究細(xì)節(jié),我們就可以看出evals是一組待執(zhí)行的函數(shù),通過Async.Parallel調(diào)用使其中每個函數(shù)都在線程池中排隊等待執(zhí)行。當(dāng)執(zhí)行時,可以看出實際上evals中的函數(shù)與awr中的函數(shù)在不同的線程中盡管由于.NET系統(tǒng)線程池的特性,部分或全部evals函數(shù)有可能在一樣的線程中執(zhí)行。Figure 7異步執(zhí)行函數(shù)復(fù)制代碼#light open System.Threading let printWithThread str=printfn"ThreadId=%d%s"Thread.CurrentThread.ManagedThreadId str let evals=let z=4.0asyncdo printWithThread"Computing z*zn"return z*z;asyncdo printWithThread"Compu
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 企業(yè)級智能零售解決方案協(xié)議
- 鋼鐵制品生產(chǎn)加工投資協(xié)議
- 傲慢與偏見節(jié)選英文閱讀與理解教學(xué)教案
- 人工智能人才培訓(xùn)合作協(xié)議
- 車間場地租賃合同
- 高中生英語閱讀理解征文
- 農(nóng)業(yè)項目管理方案
- 保密信息及非競爭協(xié)議條款
- 智能機器人研發(fā)與生產(chǎn)計劃書
- 童年小說人物解析作文
- 二副工作心得體會實習(xí)感觸
- 土壤肥料全套課件
- 旅游消費者行為學(xué)整套課件完整版電子教案課件匯總(最新)
- 學(xué)前兒童發(fā)展心理學(xué)(第3版-張永紅)教學(xué)課件1754
- 特氣供應(yīng)系統(tǒng)的規(guī)劃與設(shè)計
- 中職《機械基礎(chǔ)》全套課件(完整版)
- 勞技-中國結(jié)PPT通用課件
- 溫庭筠《望江南》ppt課件
- 口腔正畸學(xué)單詞
- 內(nèi)襯修復(fù)用HTPO管材企標(biāo)
- 部編教材一年級下冊生字筆順筆畫
評論
0/150
提交評論