con*_*low 19 math f# scope module operators
F#允许通过打开Checked模块使用经过检查的算术,它重新定义标准运算符作为检查运算符,例如:
open Checked
let x = 1 + System.Int32.MaxValue // overflow
Run Code Online (Sandbox Code Playgroud)
将导致算术溢出异常.
但是如果我想在一些小范围内使用经检查的算术,如C#允许使用关键字checked:
int x = 1 + int.MaxValue; // ok
int y = checked { 1 + int.MaxValue }; // overflow
Run Code Online (Sandbox Code Playgroud)
如何通过打开Checked模块或尽可能缩小模块来控制操作员重新定义的范围?
Bri*_*ian 19
您始终可以定义单独的运算符,或使用阴影,或使用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
Run Code Online (Sandbox Code Playgroud)
最后,另请参阅--checked+编译器选项:
http://msdn.microsoft.com/en-us/library/dd233171(VS.100).aspx
Tom*_*cek 17
这是一个复杂的(但也许是有趣的)替代方案.如果你正在写一些严肃的东西,你应该使用其中一个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
Run Code Online (Sandbox Code Playgroud)
然后你可以定义一个计算表达式构建器(这根本不是一个monad,因为操作类型完全是非标准的):
type CheckedBuilder() =
member x.Bind(v, f) = f (Ch v)
member x.Return(Ch v) = v
let checked = new CheckedBuilder()
Run Code Online (Sandbox Code Playgroud)
当你调用'bind'时,它会自动将给定的整数值包装成一个应该与checked操作一起使用的整数,因此其余代码将使用checked +和*运算符声明为成员.你最终得到这样的东西:
checked { let! a = 10000
let! b = a * 10000
let! c = b * 21
let! d = c + 47483648 // !
return d }
Run Code Online (Sandbox Code Playgroud)
这会引发异常,因为它在标记的行上溢出.如果更改数字,它将返回一个int值(因为该Return成员从Checked类型中解包数值).这是一个有点疯狂的技术:-)但我觉得它可能很有趣!
(注意checked是为将来使用而保留的关键字,因此您可能更愿意选择其他名称)