F# Checked Arithmetics Scope

前端 未结 2 1665
小鲜肉
小鲜肉 2020-12-17 09:10

F# allows to use checked arithmetics by opening Checked module, which redefines standard operators to be checked operators, for example:

open Ch         


        
相关标签:
2条回答
  • 2020-12-17 09:46

    You can always define a separate operator, or use shadowing, or use parens to create an inner scope for temporary shadowing:

    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
    

    Finally, see also the --checked+ compiler option:

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

    0 讨论(0)
  • 2020-12-17 10:04

    Here is a complicated (but maybe interesting) alternative. If you're writing something serious then you should probably use one of the Brians suggestions, but just out of curiosity, I was wondering if it was possible to write F# computation expression to do this. You can declare a type that represents int which should be used only with checked operations:

    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
    

    Then you can define a computation expression builder (this isn't really a monad at all, because the types of operations are completely non-standard):

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

    When you call 'bind' it will automatically wrap the given integer value into an integer that should be used with checked operations, so the rest of the code will use checked + and * operators declared as members. You end up with something like this:

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

    This throws an exception because it overflows on the marked line. If you change the number, it will return an int value (because the Return member unwraps the numeric value from the Checked type). This is a bit crazy technique :-) but I thought it may be interesting!

    (Note checked is a keyword reserved for future use, so you may prefer choosing another name)

    0 讨论(0)
提交回复
热议问题