成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

F#運算符定義規則總結

開發 后端
在這里我們將總結F#運算符定義規則,希望通過本文,能為大家打開一扇通往F#的窗口。

本文將討論的是F#運算符相關定義規則的問題,這些規則覆蓋大多數開發場景。希望通過本文能對大家了解F#運算符規則有所幫助。

#T#

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

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

這樣便可以這樣發送消息:

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

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

運算符重載

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

  1. // operator.fs  
  2. #light  
  3. module Operator  
  4. let (+) (a:int) (b:int) = a * b 

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

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

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

運算符的組成

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

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

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

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

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

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

前綴與中綴運算符

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

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

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

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

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

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

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

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

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

F#運算符的優先級

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

3 + 4 * 5 |> printfn "%i" // 23那么,我們自定義的運算符優先級又如何呢?F#同樣是通過運算符的首字母來決定它的優先級的,關于不同首字母的優先級高低,可以參考MSDN中《Symbol and Operator Reference (F#)》的Operator Precedence一節,它按照優先級從低到高列舉所有的運算符。

例如“除號”的優先級比“加號”高,因此:

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

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

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

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

運算符的相關性

每個運算符都有其相關性(associativity)。相關性的作用是,一旦一個表達式中連續出現優先級相同的運算符,那么它們究竟是從左向右計算(左相關),還是從右向左計算(右相關)。
例如,最普通的“除號”便是左相關的:

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

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

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

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

例如,“大于號”是左相關的,因此:

  1. let (>+) (x:int) (y:int) = x + y  
  2. let (>*) (x:int) (y:int) = x * y  
  3. 3 >+ 4 >* 5 |> printfn "%i" // 35  
  4. 3 >* 4 >+ 5 |> printfn "%i" // 17而“^”是右相關的:  
  5. let (^+) (x:int) (y:int) = x + y  
  6. let (^*) (x:int) (y:int) = x * y  
  7. 3 ^+ 4 ^* 5 |> printfn "%i" // 23  
  8. 3 ^* 4 ^+ 5 |> printfn "%i" // 27 

自然,括號可以改變運算符的相關性。

一元運算符

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

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

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

為類型定義運算符

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

  1. // 定義  
  2. type Rational(numer, denom) =  
  3.  
  4.     member r.Numer = numer  
  5.     member r.Denom = denom  
  6.  
  7.     static member (-) (x:Rational, y:Rational) =  
  8.         let n = x.Numer * y.Denom - y.Numer * x.Denom  
  9.         let d = x.Denom * y.Denom  
  10.         new Rational(n, d)  
  11.  
  12.     static member (~-) (v:Rational) = new Rational(-v.Numer, v.Denom)  
  13.  
  14. // 使用  
  15. let r1 = new Rational(1, 2)  
  16. let r2 = new Rational(2, 3)  
  17. let r3 = r1 - r2  
  18. let r4 = -r1 

至于運算符的優先級、相關性等性質,都與上文描述的保持一致。

原文標題:總結一下F#中運算符的定義規則

鏈接:http://www.cnblogs.com/JeffreyZhao/archive/2009/12/14/fsharp-operator.html

責任編輯:彭凡 來源: 51CTO
相關推薦

2025-02-24 11:16:20

2009-11-17 09:13:21

PHP運算符

2010-03-05 10:04:38

Python運算符

2009-08-14 10:16:57

C#運算符重載

2009-11-18 09:02:55

PHP運算符

2009-08-11 15:51:08

C#運算符算術運算符

2009-08-12 15:20:18

C#賦值運算符復合賦值運算符

2009-08-12 15:02:49

C#賦值運算符簡單賦值運算符

2017-09-13 10:58:51

JavaScript轉換規則

2023-04-10 08:58:13

C#關系運算符

2017-09-05 16:17:35

JavaScript運算轉換

2010-01-26 08:25:06

F#語法F#教程

2010-01-21 17:39:26

VB.NET運算符過程

2010-01-20 14:06:36

VB.NET運算符組合

2009-08-12 11:20:51

C#運算符重載

2024-02-26 15:17:20

2009-06-21 13:48:05

ShellLinux運算符

2021-12-15 10:25:57

C++運算符重載

2016-10-14 14:04:34

JAVA語法main

2009-08-12 09:30:10

C#??運算符
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91xx在线观看 | 日韩中文字幕在线播放 | 男女羞羞视频在线免费观看 | 亚洲欧美在线一区 | 午夜爽爽爽男女免费观看影院 | 天天夜夜人人 | 在线观看中文字幕视频 | 欧美一a | 免费一级黄色录像 | 久久精品久久综合 | 91麻豆精品国产91久久久久久久久 | 黄色精品视频网站 | 一区二区av | 午夜小电影 | 中文字幕在线观看第一页 | 久久一区二区精品 | 欧美黑人体内she精在线观看 | 黄网站涩免费蜜桃网站 | 欧美黄色片 | 免费看av大片 | 亚洲精品福利视频 | 久久久国产一区 | 97精品国产一区二区三区 | 亚洲欧美日韩一区二区 | 九九久久精品 | 97av在线| 日韩欧美一区二区三区在线播放 | 一区二区av | 免费成人在线网站 | av网站在线免费观看 | 少妇黄色 | 久久精品国产一区老色匹 | 中文字幕福利视频 | 欧美精品一区二区三区蜜桃视频 | 午夜电影在线播放 | 欧美视频在线播放 | 精品国产欧美一区二区 | 高清国产午夜精品久久久久久 | 午夜专区| 久久久无码精品亚洲日韩按摩 | 三级成人在线 |