F# позволяет использовать проверенную арифметику путем открытия Checked
модуль, который переопределяет стандартные операторы, чтобы быть проверенными операторами, например:
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
модуль или делает это меньшим как возможное?
Вы всегда можете определить отдельный оператор или использовать затенение, или использовать скобки для создания внутренней области для временного затенения:
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
Наконец, см. Также - отмечено +
параметр компилятора:
http://msdn.microsoft.com/en-us/library/dd233171 (VS.100) .aspx
Вот сложная (но, возможно, интересная) альтернатива. Если вы пишете что-то серьезное, вам, вероятно, следует использовать одно из предложений Брайана, но просто из любопытства мне было интересно, можно ли написать выражение вычисления 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 Операторы +
и *
объявлены как члены. Вы получите что-то вроде этого:
checked { let! a = 10000
let! b = a * 10000
let! c = b * 21
let! d = c + 47483648 // !
return d }
Это вызывает исключение, потому что оно выходит за пределы отмеченной строки. Если вы измените число, он вернет значение int
(поскольку член Return
разворачивает числовое значение из типа Checked
). Это немного сумасшедший прием :-), но я подумал, что это может быть интересно!
(Примечание отмечено
- ключевое слово, зарезервированное для использования в будущем, поэтому вы можете выбрать другое имя)