F#: Why aren't option types compatible with nu

2020-02-10 19:08发布

问题:

Why aren't option types like "int option" compatible with nullable types like "Nullable"?

I assume there is some semantic reason for the difference, but I can't figure what that is.

An option in F# is used when a value may or may not exist. An option has an underlying type and may either hold a value of that type or it may not have a value.

http://msdn.microsoft.com/en-us/library/dd233245%28VS.100%29.aspx

That sure sounds like the Nullable structure.

回答1:

Because of the runtime representation choice for System.Nullable<'T>.

Nullable tries to represent the absent of values by the null pointer, and present values by pointers to those values.

(new System.Nullable<int>() :> obj) = null
|> printfn "%b" // true

(new System.Nullable<int>(1) :> obj).GetType().Name
|> printfn "%s" // Int32

Now consider strings. Unfortunately, strings are nullable. So this is valid:

null : string

But now a null runtime value is ambiguous - it can refer to either the absence of a value or a presence of a null value. For this reason, .NET does not allow constructing a System.Nullable<string>.

Contrast this with:

(Some (null : string) :> obj).GetType().Name
|> printfn "%s" // Option`1

That being said, one can define a bijection:

let optionOfNullable (a : System.Nullable<'T>) = 
    if a.HasValue then
        Some a.Value
    else
        None

let nullableOfOption = function
    | None -> new System.Nullable<_>()
    | Some x -> new System.Nullable<_>(x)

If you observe the types, these functions constrain 'T to be a structure and have a zero-argument constructor. So perhaps F# compiler could expose .NET functions receiving/returning Nullable<'T> by substituting it for an Option<'T where 'T : struct and 'T : (new : unit -> 'T)>, and inserting the conversion functions where necessary..



回答2:

The two have different semantics. Just to name one, Nullable is an idempotent data constructor that only works on value types, whereas option is a normal generic type. So you can't have a

Nullable<Nullable<int>>

but you can have an

option<option<int>>

Generally, though there are some overlapping scenarios, there are also things you can do with one but not the other.



回答3:

Key difference is that must test the option type to see if it has a value. See this question for a good description of its semantics: How does the option type work in F#



回答4:

Again, this is from my limited understanding, but the problem probably lies in how each gets rendered in the IL. The "nullable" structure probably gets handled slightly different from the option type.

You will find that the interactions between various .Net languages really boils down to how the IL gets rendered. Mostof the time it works just fine but on occasion, it causes issues. (check out this). Just when you thought it was safe to trust the level of abstraction. :)



标签: f# null