Closed utterances-bot closed 3 years ago
It turns out that you can actually create a value of your Bottom
type using let rec
:
type Bottom = private Bottom of Bottom
let rec b = Bottom b
match b with
| Bottom b' -> printfn "Yo!"
There is even a paper from the old days of F# (2006) explaining how let rec
works on values: Initializing Mutually Referential Abstract Objects: The Value Recursion Challenge
I had considered the possibility that such a value could have a reference to itself, but I thought that it would require mutation to create. Thanks for tell me about this :)
Since you posted this, we've had a nice discussion in the language suggestion. Conclusion (from my pov): the CLR does not allow a type to be at the bottom of the inheritance chain, which disallows a Bottom
type.
The two main properties ((1) cannot be instantiated, (2) sits at the bottom of the inheritance chain) can only be approximated, copied from that thread:
A type that cannot be instantiated
type Bottom<'T when 'T : not struct and 'T : unmanaged> =
| Bottom of 'T
static member create() = Bottom(Unchecked.defaultof<_>)
Using Bottom.create()
will, however, throw FS1202, because the ambiguity cannot be resolved.
A normal non-instantiable type
type Bottom =
// will return null
static member create() = Unchecked.defaultof<Bottom>
You cannot create Bottom
the normal way as it does not have public constructors. But this type can be used in normal code as it resolves just fine. However, property (2) cannot be resolved here, or anywhere else, as "a type that is a derived type from every other type" cannot exist in CLR.
Using generics
module Bottom =
// will never return, but implies null or zero for any type
let create() =
exn "Unreachable code" |> raise
Unchecked.defaultof<_>
This method uses the same method as raise
and comes close to satisfying property (2) through isomorphism. However, as noted before, the CLR does not allow a type like Bottom
, so this is as close as one can get (I think).
Implicitly, the type System.Void
has these properties, but F# prevents you from using it, as does C#. It's only there as a courtesy to the type system.
Thanks for your comment here and your comments in that language suggestion. I agree with your conclusions. Thanks for the summary :)
Bottom Type in F
https://tysonwilliams.coding.blog/2020-09-21_bottom_type_in_fsharp