2010-02-16 16 views
18

F # permette di utilizzare aritmetica controllato da aprire Checked modulo, che ridefinisce operatori standard da verificare operatori, ad esempio:F # Controllato Arithmetics Scope

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

si tradurrà eccezione overflow aritmetico.

Ma cosa succede se voglio usare aritmetica controllato in qualche campo di applicazione, come C# permette con parola chiave checked:

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

Come posso controllare la portata degli operatori ridefinizione aprendo modulo Checked o renderlo più piccolo come possibile?

+0

Al contrario, è possibile invocare "controllato" su tutte le dichiarazioni in un progetto C#? –

+2

@Heath Hunnicutt - L'inverso può essere eseguito con le opzioni del compilatore, sia nell'IDE che nella riga di comando. –

risposta

18

si può sempre definire un operatore indipendente, o utilizzare shadowing, o l'uso parentesi contenute per creare un ambito interno per ombreggiatura temporanea:

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 

Infine, si veda anche l'opzione --checked+ compilatore:

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

+2

nice, thanks =) – ControlFlow

16

Ecco un'alternativa complicata (ma forse interessante). Se stai scrivendo qualcosa di serio, probabilmente dovresti usare uno dei suggerimenti di Brians, ma solo per curiosità, mi chiedevo se fosse possibile scrivere l'espressione di calcolo F # per farlo. È possibile dichiarare un tipo che rappresenta int che dovrebbe essere utilizzato solo con operazioni controllato:

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 

Quindi è possibile definire un generatore di espressioni di calcolo (questo non è davvero una monade a tutti, perché i tipi di operazioni sono completamente non standard):

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

Quando si chiama 'bind' che andrà a capo automaticamente il dato valore intero in un numero intero che deve essere utilizzato con checked operazioni, in modo che il resto del codice utilizzerà controllato + e * operatori dichiarato come membri. Si finisce con qualcosa di simile:

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

Ciò genera un'eccezione perché si trabocca sulla linea contrassegnata. Se si modifica il numero, verrà restituito un valore int (poiché il membro Return scartina il valore numerico dal tipo Checked). Questa è una tecnica un po 'pazza :-) ma ho pensato che potrebbe essere interessante!

(Nota checked è una parola chiave riservata per uso futuro, quindi si può preferire la scelta di un altro nome)

+0

+1 per un approccio tipografico – Dario

+0

È fantastico. – kvb

+5

Non è poi così bello. Puoi scrivere 'checked {return Int32.MaxValue + 1}' e sarà effettivamente deselezionato, perché per creare un numero _checked_, devi passarlo a 'let!' Prima ... –