2010-02-16 43 views
18

F#允許通過打開Checked模塊,該模塊重新定義標準運算符進行檢查運營商,例如使用檢查碼運算:F#經過運算在範圍

open Checked 
let x = 1 + System.Int32.MaxValue // overflow 

將導致算術溢出異常。

但是,如果我想使用檢查算術在一些小的範圍內,如C#與關鍵字checked允許什麼:

int x = 1 + int.MaxValue;    // ok 
int y = checked { 1 + int.MaxValue }; // overflow 

打開Checked模塊或使其體積更小,我如何控制運營商重新定義的範圍可能?

+0

相反,是有可能調用在C#項目的所有語句「檢查」? –

+2

@Heath Hunnicutt - 可以在IDE或命令行中使用編譯器選項完成相反的操作。 –

回答

18

你總是可以定義一個單獨的操作,或者使用陰影,或使用的括號創建臨時遮蔽內部範圍:

let f() = 
    // define a separate operator 
    let (+.) x y = Checked.(+) x y 
    try 
     let x = 1 +. System.Int32.MaxValue 
     printfn "ran ok" 
    with e -> 
     printfn "exception" 
    try 
     let x = 1 + System.Int32.MaxValue 
     printfn "ran ok" 
    with e -> 
     printfn "exception" 
    // shadow (+) 
    let (+) x y = Checked.(+) x y 
    try 
     let x = 1 + System.Int32.MaxValue 
     printfn "ran ok" 
    with e -> 
     printfn "exception" 
    // shadow it back again 
    let (+) x y = Operators.(+) x y 
    try 
     let x = 1 + System.Int32.MaxValue 
     printfn "ran ok" 
    with e -> 
     printfn "exception" 
    // use parens to create a scope 
    (
     // shadow inside 
     let (+) x y = Checked.(+) x y 
     try 
      let x = 1 + System.Int32.MaxValue 
      printfn "ran ok" 
     with e -> 
      printfn "exception" 
    )    
    // shadowing scope expires 
    try 
     let x = 1 + System.Int32.MaxValue 
     printfn "ran ok" 
    with e -> 
     printfn "exception" 


f()  
// output: 
// exception 
// ran ok 
// exception 
// ran ok 
// exception 
// ran ok 

最後,也見--checked+編譯器選項:

http://msdn.microsoft.com/en-us/library/dd233171(VS.100).aspx

+2

不錯,謝謝=) – ControlFlow

16

這是一個複雜的(但也許有趣)的選擇。如果你寫的東西很嚴肅,那麼你應該使用Brians的一個建議,但出於好奇,我想知道是否可以編寫F#計算表達式來完成這個任務。你可以聲明表示int這樣一種類型,只應在檢查操作中使用:

type CheckedInt = Ch of int with 
    static member (+) (Ch a, Ch b) = Checked.(+) a b 
    static member (*) (Ch a, Ch b) = Checked.(*) a b 
    static member (+) (Ch a, b) = Checked.(+) a b 
    static member (*) (Ch a, b) = Checked.(*) a b 

然後,你可以定義一個計算表達式生成器(這是不是一個真正的單子可言,因爲類型的操作是完全非標):

type CheckedBuilder() = 
    member x.Bind(v, f) = f (Ch v)  
    member x.Return(Ch v) = v 
let checked = new CheckedBuilder() 

當你調用「綁定」,它會自動換行給定的整數值,應與checked操作中使用一個整數,所以代碼的其餘部分將使用檢查+*運營商宣佈爲成員。你最終會遇到這樣的問題:

checked { let! a = 10000 
      let! b = a * 10000 
      let! c = b * 21 
      let! d = c + 47483648 // ! 
      return d } 

這會拋出一個異常,因爲它在標記線上溢出。如果更改號碼,它將返回一個int值(因爲Return成員從Checked類型中解開數字值)。這有點瘋狂的技術:-)但我認爲它可能很有趣!

(注checked是一個關鍵字留作將來使用,所以你可能更喜歡選擇的另一個名字)

+0

+1類型安全的方法 – Dario

+0

太棒了。 – kvb

+5

雖然不是那麼棒。你可以寫'checked {return Int32.MaxValue + 1}',它實際上會被取消選中,因爲要創建一個數字_checked_,你需要首先將它傳遞給'let!'... –