2010-02-16 17 views
18

F # ermöglicht durch Öffnen Checked Modul geprüft arithmetics zu verwenden, die Standard-Operatoren definiert Betreiber geprüft werden, zum Beispiel:F # Geprüft Arithmetics Scope

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

wird arithmetischer Überlauf Ausnahme führen.

Aber was, wenn ich will in einigen kleinen Umfang geprüft arithmetics verwenden, wie C# mit Stichwort checked erlaubt: Wie

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

kann ich den Umfang der Betreiber Neudefinition steuern, indem Checked Modul zu öffnen oder es kleiner machen als möglich?

+0

Umgekehrt ist es möglich, in einem C# -Projekt auf alle Aussagen zum Aufrufen „geprüft“? –

+2

@Heath Hunnicutt - Die Umkehrung kann mit Compiler-Optionen erreicht werden, entweder in der IDE oder in der Befehlszeile. –

Antwort

18

Sie können jederzeit über einen separaten Operator definieren, oder Shadowing verwenden oder Verwendung parens einen inneren Raum für temporäre Verschattung zu erstellen:

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 

Schließlich sieht auch die --checked+ Compiler-Option:

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

+2

nice, thanks =) – ControlFlow

16

Hier ist eine komplizierte (aber vielleicht interessante) Alternative. Wenn Sie etwas ernsthaftes schreiben, sollten Sie wahrscheinlich einen der Brians-Vorschläge verwenden, aber nur aus Neugierde habe ich mich gefragt, ob es möglich ist, einen F # -Berechnungsausdruck dafür zu schreiben. Sie können einen Typen deklarieren, die int darstellt, die nur mit karierter Operation verwendet werden sollen:

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 

Dann können Sie einen Berechnungsausdruck Builder definieren (dies überhaupt nicht wirklich eine Monade ist, weil die Arten von Operationen vollständig sind nicht-Standard):

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

Wenn Sie ‚binden‘ nennen wird es automatisch den gegebenen ganzzahligen Wert in eine ganze Zahl wickeln, die mit checked Operationen verwendet werden soll, so wird der Rest des Codes + und * Operatoren überprüft als Mitglieder deklariert. Sie am Ende mit etwas wie folgt aus:

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

Dies löst eine Ausnahme, weil es auf der markierten Linie überläuft. Wenn Sie die Nummer ändern, wird ein int Wert zurückgegeben (da das Return Element den numerischen Wert aus dem Checked Typ auspackt). Das ist ein bisschen verrückte Technik :-), aber ich dachte, es könnte interessant sein!

(Anmerkung checked ist ein Stichwort für die zukünftige Verwendung reserviert, so dass Sie einen anderen Namen wählen bevorzugen)

+0

+1 für einen typsicheren Ansatz – Dario

+0

Das ist genial. – kvb

+5

Es ist aber nicht so toll. Sie können 'checked {return Int32.MaxValue + 1}' schreiben und es wird tatsächlich deaktiviert, denn um eine Zahl _checked_ zu erstellen, müssen Sie sie an 'let!' Übergeben. –

Verwandte Themen