繁体   English   中英

F#检查算术范围

[英]F# Checked Arithmetics Scope

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模块或尽可能缩小它来控制操作员重新定义的范围?

您始终可以定义单独的运算符,或使用阴影,或使用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+ compiler选项:

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

这是一个复杂的(但也许是有趣的)替代方案。 如果你正在写一些严肃的东西,你应该使用其中一个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

然后你可以定义一个计算表达式构建器(这根本不是一个monad,因为操作类型完全是非标准的):

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类型中解开数值)。 这是一个有点疯狂的技术:-)但我觉得它可能很有趣!

(注意checked是保留供将来使用的关键字,因此您可能更愿意选择其他名称)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM