Reputation: 2066
When try the following code in F# interactive
> let a = None
- let b = (a, Some 1);;
> b;;
val it : 'a option * int option = (null, Some 1)
It show that b has type 'a option * int option, the type of b is correct. However, the value of first element of the tuple is null, not None, Why?
When try to verify the first element of the tuple whether really is null
printfn "%s" (match b with (null, _) -> "null" | _ -> "not null");;
it gives the following error
error FS0043: The type ''a option' does not have 'null' as a prope r value
When try to get the fisrt value in tuple,
let c = fst b;;
it gives
error FS0030: Value restriction. The value 'c' has been inferred to have generic type val c : '_a option Either define 'c' as a simple data term, make it a function with explicit argume nts or, if you do not intend for it to be generic, add a type annotation.
Upvotes: 1
Views: 836
Reputation: 5004
The internal representation for the value None
is indeed a null
value. But that is the internal representation, the compiler identifies null
and None
as two completely different values, so you cannot compare them as they are different types. That is why you get: error FS0043
.
This is actually something to be careful of:
let a = None
let b = (a, Some 1)
let print v = printfn "%A" v
sprintf "%A" a |> print // "<null>"
sprintf "%A" b |> print // "(None, Some 1)"
sprintf "%O" a |> print // "<null>"
sprintf "%O" b |> print // "(, Some(1))"
string a |> print // ""
string b |> print // "(, Some(1))"
a .IsNone |> print // true
a .IsSome |> print // false
a .GetType() |> print // System.NullReferenceException: Object reference not set to an instance of an object.
a .ToString() |> print // System.NullReferenceException: Object reference not set to an instance of an object.
(fst b).ToString() |> print // System.NullReferenceException: Object reference not set to an instance of an object.
(snd b).ToString() |> print // "Some(1)"
... because calling some methods on a None
value throws the dreaded NullReference
Exception and converting to string is also erratic.
Regarding error FS0030
basically values cannot be generic. This has been discussed many times in SO.
Values from Discriminated Unions seem to be treated in a special way, they seem to be granted an exception, for instance these are generic and still Ok:
type MyDU<'A, 'B> =
| ValNo
| ValA of 'A
| ValB of 'B
let v1 = ValNo // MyDU<'a,'b> double generic but Ok
let v2 = ValA 1 // MyDU<int,'a> generic but Ok
let v3 = ValB 1 // MyDU<'a,int> generic but Ok
but these are not Ok
let valNo() = ValNo
let valA a = ValA a
let valB b = ValB b
let w1 = valNo() // MyDU<'_a,'_b> double generic not Ok
let w2 = valA 1 // MyDU<int,'_a> generic not Ok
let w3 = valB 1 // MyDU<'_a,int> generic not Ok
Upvotes: 6