Подтвердить что ты не робот

F # Проверяемая область арифметики

F # позволяет использовать проверенную арифметику, открывая модуль Checked, который переопределяет стандартные операторы для проверки операторов, например:

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

приведет к исключению арифметического переполнения.

Но что, если я хочу использовать проверенную арифметику в небольшом объеме, например, С# с ключевым словом Checked:

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

Как я могу контролировать область переопределения операторов, открыв модуль Checked или уменьшив его насколько возможно?

4b9b3361

Ответ 1

Вы всегда можете определить отдельный оператор или использовать затенение или использовать parens для создания внутренней области для временного затенения:

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

Вот сложная (но, может быть, интересная) альтернатива. Если вы пишете что-то серьезное, то вы, вероятно, должны использовать одно из предложений 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()  

Когда вы вызываете "bind", он автоматически переносит заданное целочисленное значение в целое число, которое должно использоваться с операциями checked, поэтому в остальной части кода будут использоваться проверенные операторы + и *, объявленные как члены, Вы получите что-то вроде этого:

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

Это генерирует исключение, поскольку оно переполняется на отмеченной строке. Если вы измените номер, он вернет значение int (поскольку член Return разворачивает числовое значение из типа checked). Это немного сумасшедшая техника:-), но я подумал, что это может быть интересно!

(Примечание checked - это ключевое слово, зарезервированное для использования в будущем, поэтому вы можете выбрать другое имя)