日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

总结一下F#中运算符的定义规则

發(fā)布時間:2025/4/5 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 总结一下F#中运算符的定义规则 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

F#允許開發(fā)人員定義或重載各類運算符,合理利用這一規(guī)則可以讓編程變得方便,讓代碼更容易閱讀。例如,在使用F#的MailboxProcessor的時候,我會習(xí)慣于定義一個運算符來代替顯式的Post操作:

let (>>) m (agent: MailboxProcessor<_>) = agent.Post m

這樣便可以這樣發(fā)送消息:

let agent = MailboxProcessor.Start(fun o -> async { o |> ignore }); "hello world" >> agent

不過,F#的運算符定義規(guī)則較為復(fù)雜,要搞清楚編譯器的整體處理方式著實花費了一番功夫。比較奇怪的是,即便是《Expert F#》中對于這個話題也沒有詳細的敘述——更夸張的是MSDN的文檔也相當馬虎,甚至有代碼缺失以及與試驗不符情況(因為還沒有正式發(fā)布?)。于是我連看帶試,最終打算總結(jié)一番,作為備忘的同時也算是補充互聯(lián)網(wǎng)資源。

運算符重載

F#中允許在global級別重載一個運算符,甚至“覆蓋”原有的定義。例如,我們可以寫一個Operator模塊,其中只有一個“加號”的定義:

// operator.fs #lightmodule Operatorlet (+) (a:int) (b:int) = a * b

我們可以在另一個模塊中引入Operator模塊,于是兩個整數(shù)的“加法”便可以得出乘法的效果了:

1 + 2 |> printfn "%i" // 2

從中也可以看出,胡亂重載運算符實在是一種沒事找事的方式。因此,現(xiàn)在這篇文章純粹都是在“談技術(shù)”,所有的內(nèi)容,包括示例都代表“最佳實踐”。

運算符的組成

在F#中,自定義運算符可以由以下字符組成:

! % & * + - . / < = > ? @ ^ | ~

目前在MSDN中,《Operator Overloading (F#)》一文寫到“$”也可以作為運算符的組成,不過最新的F#編譯器(v1.9.7.4)中會對此作出“警告”,表示以后它將成為一個F#的保留字,不允許用作運算符。

在F#中,每個運算符不限長度。也就是說,如果您喜歡的話,完全可以定義這樣的一個運算符來表示整數(shù)乘法:

let (!%&*+-./<=>?@^|~!%&*+-./<=>?@^|~) (x:int) (y:int) = x * y

F#會將運算符編譯為程序集中具體的方法,其命名遵循一定規(guī)則。不過在使用時我們并不需要關(guān)心這些。如果您對這方面的具體信息感興趣,可以參考MSDN中《Operator Overloading (F#)》一文。

前綴與中綴運算符

前綴(prefix)運算符,表示運算符出現(xiàn)在運算數(shù)之前,例如“負號”便是個前綴運算符:

let a = 1 -a |> printfn "%i" // -1

中綴(postfix)運算符,表示運算符出現(xiàn)在兩個運算數(shù)之間,例如最常見的“加法”便是個中綴運算符:

1 + 2 |> printfn "%i" // 3

在自定義運算符時,F#并不允許我們指定某個運算符是前綴還是中綴運算符,編譯器會自動根據(jù)運算符的“首字母”來決定它是前綴還是中綴的。例如,首字母為“感嘆號”的運算符便是“前綴”運算符:

let (!+) (x:int) (y:int) = x + y

根據(jù)這個規(guī)則,我們只能將“!+”作為前綴運算符來使用:

1 (!+) 2 |> printfn "%i" // 編譯失敗! !+ (!+ 1 2) 3 |> printfn "%i" // 6

關(guān)于某個字母表示前綴還是中綴運算符,您可以參考《Operator Overloading (F#)》一文中的表格。可以發(fā)現(xiàn),大部分運算符都是中綴的,而只有少數(shù)是前綴運算符。至于后綴運算符……F#并不支持后綴運算符。

運算符的優(yōu)先級

每個運算符有其自己的優(yōu)先級(precedence),優(yōu)先級表示一個表達式中連續(xù)出現(xiàn)多個運算符時,究竟哪個運算符先生效。例如,我們都知道“先乘除后加減”:

3 + 4 * 5 |> printfn "%i" // 23

那么,我們自定義的運算符優(yōu)先級又如何呢?F#同樣是通過運算符的首字母來決定它的優(yōu)先級的,關(guān)于不同首字母的優(yōu)先級高低,可以參考MSDN中《Symbol and Operator Reference (F#)》的Operator Precedence一節(jié),它按照優(yōu)先級從低到高列舉所有的運算符。

例如“除號”的優(yōu)先級比“加號”高,因此:

let (+/) (x:int) (y:int) = x / y let (/+) (x:int) (y:int) = x + y4 + 4 / 2 |> printfn "%i" // 6 4 /+ 4 +/ 2 |> printfn "%i" // 4

值得注意的是,如果兩個運算符的首字母相同,則F#便認為兩個運算符的優(yōu)先級相同,而不在比較它們后續(xù)字符的優(yōu)先級高低。不過在優(yōu)先級的判定中有個特例,那就是“點”,它并不參與優(yōu)先級的比較中,此時便以后面的字符為準了:

let (.+) (x:int) (y:int) = x + y let (..*) (x:int) (y:int) = x * y// 仍然是“先乘除后加減” 3 .+ 4 ..* 5 |> printfn "%i" // 23 3 ..* 4 .+ 5 |> printfn "%i" // 17

當然,括號可以改變運算符的優(yōu)先級,這點再正常不過了。還有一點,便是“轉(zhuǎn)發(fā)”操作(即本文代碼中出現(xiàn)的“|>”),它以“|”作為首字母。根據(jù)規(guī)則,它的優(yōu)先級是很低的(在自定義運算符中是最低的)。因此,無論我們左側(cè)的表達式中使用了什么樣的運算符,都是最后才進行“轉(zhuǎn)發(fā)”操作。

運算符的相關(guān)性

每個運算符都有其相關(guān)性(associativity)。相關(guān)性的作用是,一旦一個表達式中連續(xù)出現(xiàn)優(yōu)先級相同的運算符,那么它們究竟是從左向右計算(左相關(guān)),還是從右向左計算(右相關(guān))。

例如,最普通的“除號”便是左相關(guān)的:

4 / 2 / 2 |> printfn "%i" // 1

而List操作的“連接符”(連接單個元素與一個列表)便是右相關(guān)的:

1 :: 2 :: 3 :: [] |> printfn "%A" // [1; 2; 3]

在F#中,運算符的相關(guān)性也是由首字母決定的,您可以在MSDN中《Symbol and Operator Reference (F#)》的Operator Precedence一節(jié)查到所有字符的相關(guān)性。

例如,“大于號”是左相關(guān)的,因此:

let (>+) (x:int) (y:int) = x + y let (>*) (x:int) (y:int) = x * y3 >+ 4 >* 5 |> printfn "%i" // 35 3 >* 4 >+ 5 |> printfn "%i" // 17

而“^”是右相關(guān)的:

let (^+) (x:int) (y:int) = x + y let (^*) (x:int) (y:int) = x * y3 ^+ 4 ^* 5 |> printfn "%i" // 23 3 ^* 4 ^+ 5 |> printfn "%i" // 27

自然,括號可以改變運算符的相關(guān)性。

一元運算符

之前我們討論的大都是二元運算符(即需要兩個運算數(shù)),不過有一個字符比較特殊,它便是“~”,我們可以利用它來定義一個“一元運算符”:

let (~-) (x:int) = x + 1let a = 1 -a |> printfn "%i" // 2

這效果是不是很神奇?因此,如果您要重載現(xiàn)有的運算符,請一定三思而后行。

為類型定義運算符

之前我們一直在討論“全局”級別的運算符。事實上,運算符也可以定義在某個類型內(nèi)部。例如:

// 定義 type Rational(numer, denom) =member r.Numer = numermember r.Denom = denomstatic member (-) (x:Rational, y:Rational) =let n = x.Numer * y.Denom - y.Numer * x.Denomlet d = x.Denom * y.Denomnew Rational(n, d)static member (~-) (v:Rational) = new Rational(-v.Numer, v.Denom)// 使用 let r1 = new Rational(1, 2) let r2 = new Rational(2, 3) let r3 = r1 - r2 let r4 = -r1

至于運算符的優(yōu)先級、相關(guān)性等性質(zhì),都與上文描述的保持一致。

轉(zhuǎn)載于:https://www.cnblogs.com/JeffreyZhao/archive/2009/12/14/fsharp-operator.html

總結(jié)

以上是生活随笔為你收集整理的总结一下F#中运算符的定义规则的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。