2010-02-16 7 views
18

F # permite usar la aritmética controladas por la apertura de Checked módulo, que redefine operadores estándar de comprobación operadores, por ejemplo:F # A cuadros Arithmetics Alcance

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

resultará excepción de desbordamiento aritmético.

Pero lo que si quiero usar la aritmética controladas en algún pequeño alcance, como C# permite la palabra clave checked:

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

¿Cómo puedo controlar el alcance de los operadores redefinición abriendo Checked módulo o hacerlo más pequeño como ¿posible?

+0

Por el contrario, es posible invocar "marcada" en todas las declaraciones en un proyecto de C#? –

+2

@Heath Hunnicutt: lo contrario se puede lograr con las opciones del compilador, ya sea en el IDE o en la línea de comandos. –

Respuesta

18

siempre se puede definir un operador independiente, o utilizar el sombreado, o el uso que parens para crear un ámbito interno para remedar temporal:

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 

Por último, consulta la opción --checked+ compilador:

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

+2

nice, thanks =) – ControlFlow

16

Aquí hay una alternativa complicada (pero tal vez interesante). Si estás escribiendo algo serio, entonces probablemente deberías usar una de las sugerencias de Brians, pero solo por curiosidad, me preguntaba si era posible escribir la expresión de cálculo F # para hacer esto. Se puede declarar un tipo que representa int que debe ser utilizado únicamente con operaciones controladas:

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 

A continuación, se puede definir un generador de expresiones de cálculo (esto no es realmente una mónada en absoluto, porque los tipos de operaciones son completamente no estándar):

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

Cuando se llama 'bind' que se ajustará automáticamente el valor entero dado en un entero que se debe utilizar con checked operaciones, por lo que el resto del código utilizará comprobado + y * operadores declarados como miembros. Usted termina con algo como esto:

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

Esto arroja una excepción porque se desborda en la línea marcada. Si cambia el número, devolverá un valor int (porque el miembro Return desenvuelve el valor numérico del tipo Checked). Esta es una técnica un poco loca :-) ¡pero pensé que podría ser interesante!

(Nota checked es una palabra clave reservada para uso futuro, por lo que prefieren elegir otro nombre)

+0

+1 para un enfoque tipo seguro – Dario

+0

Eso es increíble. – kvb

+5

Aunque no es tan genial. Puede escribir 'checked {return Int32.MaxValue + 1}' y estará realmente desmarcado, porque para hacer un número _checked_, necesita pasarlo a 'let!' Primero ... –

Cuestiones relacionadas