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..
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…