Int Option instead of Int in F#

2019-08-09 17:50发布

问题:

I am having trouble with the following:

let safeDiv x y = 
  match (x,y) with
  | (_, Some 0) -> None
  | (Some xx, Some yy) -> Some (xx/yy)
  | _ -> None

When I go to run this simple function in the interactive window of Visual Studio like so:

safeDiv 4 2

I get the following error...

This expression was expected to have type int option but here has type int.

Could it be I'm meant to use safeDiv Some(4) Some(2)? This doesn't work either...

回答1:

Ok, this is overkill but I actually did something similar to this recently.

First I defined a computation expression builder for the option type:

type OptionBuilder() =
    member this.Bind(x, f) = Option.bind f x
    member this.Return(x) = Some x
    member this.ReturnFrom(x) = x

let opt = new OptionBuilder()

And then I defined a function sub of type float -> float -> float option

let sub x y = if y = 0.0 then None else Some (x / y)

And finally I used the OptionBuilder to define saveDiv as float option -> float option -> float option

let safeDiv x y = opt { let! a = x
                        let! b = y
                        return! sub a b }

You can read more about computation expressions on wikibooks: http://en.wikibooks.org/wiki/F_Sharp_Programming/Computation_Expressions

And if you want to dive deeper into the theory behind this, you can read this paper by Tomas Petricek and Don Syme: http://www.cl.cam.ac.uk/~tp322/drafts/notations.pdf



回答2:

Your second version was close.

It should be

safeDiv (Some(4)) (Some(2))

The extra brackets are required to make sure that functions are applied in the correct order.



回答3:

You constructed a function that has the signature safeDiv : int option -> int option -> int option. You need to use an entry like safeDiv (Some 4) (Some 2) to use your function as is.



回答4:

The problem is in the matching of (4, 2), of type int*int, with the expressions (_, Some 0) and (Some xx, Some yy). The whole function can be simplified:

let safeDiv x y = 
    match (x,y) with
    | (_, 0) -> None
    | (_, _) -> Some (x/y)

Making the following call valid

safeDiv 4 2