2 people like it.
Like the snippet!
Reimplementation of C# Nullable type
Type-safe Nullable in F# featuring:
arithmetic operations on primitive types,
structural equality/comparison,
null-coalescing operator,
explicit type conversion to the underlying type,
throwing an exception in exceptional condition,
`nullable` computation expression,
and etc.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
|
// XXX Uncomment the following line:
//[<Struct>]
type FSharpNullable<'T when 'T : struct> =
| Value of 'T
| Null
member this.HasValue =
match this with
| Null -> false
| Value _ -> true
static member inline op_Explicit(this) : 'T =
match this with
| Null -> raise <| System.InvalidOperationException(
"Nullable object must have a value.")
| Value x -> x
static member inline (<??>) (lhs, rhs) =
match lhs with
| Null -> rhs
| Value x -> x
module FSharpNullable =
let bind f x =
match x with
| Null -> Null
| Value x' -> f x'
type FSharpNullableBuilder() =
member __.Bind(x, f) = x |> FSharpNullable.bind f
member __.Return(x) = Value x
[<AutoOpen>]
module FSharpNullableComputationExpression =
let nullable = FSharpNullableBuilder()
[<AutoOpen>]
module private FSharpNullableOps =
let inline add (a: FSharpNullable<'T>) (b: FSharpNullable<'T>) : FSharpNullable<'T> =
nullable {
let! x = a
let! y = b
return x + y
}
let inline subtract (a: FSharpNullable<'T>) (b: FSharpNullable<'T>) : FSharpNullable<'T> =
nullable {
let! x = a
let! y = b
return x - y
}
let inline multiply (a: FSharpNullable<'T>) (b: FSharpNullable<'T>) : FSharpNullable<'T> =
nullable {
let! x = a
let! y = b
return x * y
}
let inline divide (a: FSharpNullable<'T>) (b: FSharpNullable<'T>) : FSharpNullable<'T> =
nullable {
let! x = a
let! y = b
return x / y
}
type FSharpNullable<'T when 'T : struct> with
static member inline ( + ) (lhs, rhs) = add lhs rhs
static member inline (.+.) (lhs, rhs) = add lhs rhs
static member inline ( +.) (lhs, rhs) = add (Value lhs) rhs
static member inline (.+ ) (lhs, rhs) = add lhs (Value rhs)
static member inline ( - ) (lhs, rhs) = subtract lhs rhs
static member inline (.-.) (lhs, rhs) = subtract lhs rhs
static member inline ( -.) (lhs, rhs) = subtract (Value lhs) rhs
static member inline (.- ) (lhs, rhs) = subtract lhs (Value rhs)
static member inline ( * ) (lhs, rhs) = multiply lhs rhs
static member inline (.*.) (lhs, rhs) = multiply lhs rhs
static member inline ( *.) (lhs, rhs) = multiply (Value lhs) rhs
static member inline (.* ) (lhs, rhs) = multiply lhs (Value rhs)
static member inline ( / ) (lhs, rhs) = divide lhs rhs
static member inline (./.) (lhs, rhs) = divide lhs rhs
static member inline ( /.) (lhs, rhs) = divide (Value lhs) rhs
static member inline (./ ) (lhs, rhs) = divide lhs (Value rhs)
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
|
// Prepend/append `.` to the operator to let the compiler know that the left/right hand side of operand is of Nullable.
let a = Value 13 .+. Value 29 // val b : FSharpNullable<int> = Value 42
// If both sides of the operator are of Nullable, you can omit `.`.
let b = Value 19 + Value 23 // val a : FSharpNullable<int> = Value 42
// Supports structural equality.
a = b // val it : bool = true
// Supports structural comparison.
Value 2 < Value 3 // val it : bool = true
// `.+` denotes the LHS is of FSharpNullable and the RHS non-nullable.
let c = a .+ 42 // val c : FSharpNullable<int> = Value 84
// `+.` denotes the LHS is of non-nullable and the RHS of FSharpNullable.
let c = 42 +. a // val c : FSharpNullable<int> = Value 84
// Null is such a scary thing so that it turns everything it touches into Null.
let n = a + Null // val n : FSharpNullable<int> = Null
// Null-coalescing operator evaluates to the LHS if the LHS is not Null..
a + c <??> 42 // val it : int = 126
// Null-coalescing operator evaluates to the RHS if the LHS is Null.
a + c + n <??> 42 // val it : int = 42
// Supports C#-like property.
a.HasValue // val it : bool = true
n.HasValue // val it : bool = false
// Explicit type conversion to the underlying type.
int a // val it : int = 42
// Type-safety.
int64 a // error FS0001: The type 'FSharpNullable<int>' does not support a conversion to the type 'int64'
int64 (Value 42L) // val it : int64 = 42L
// Can't type-convert Null in any case.
int n // System.InvalidOperationException: Nullable object must have a value.
|
union case FSharpNullable.Value: 'T -> FSharpNullable<'T>
union case FSharpNullable.Null: FSharpNullable<'T>
val this : FSharpNullable<'T> (requires value type)
member FSharpNullable.HasValue : bool
Full name: Script.FSharpNullable`1.HasValue
static member FSharpNullable.op_Explicit : this:FSharpNullable<'T> -> 'T
Full name: Script.FSharpNullable`1.op_Explicit
val raise : exn:System.Exception -> 'T
Full name: Microsoft.FSharp.Core.Operators.raise
namespace System
Multiple items
type InvalidOperationException =
inherit SystemException
new : unit -> InvalidOperationException + 2 overloads
Full name: System.InvalidOperationException
--------------------
System.InvalidOperationException() : unit
System.InvalidOperationException(message: string) : unit
System.InvalidOperationException(message: string, innerException: exn) : unit
val x : 'T (requires value type)
val lhs : FSharpNullable<'a> (requires value type)
val rhs : 'a (requires value type)
val x : 'a (requires value type)
type FSharpNullable<'T (requires value type)> =
| Value of 'T
| Null
member HasValue : bool
static member ( + ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( + ))
static member ( /. ) : lhs:'a * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires member ( / ) and value type)
static member ( / ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( / ))
static member ( ./ ) : lhs:FSharpNullable<'a> * rhs:'a -> FSharpNullable<'a> (requires member ( / ) and value type)
static member ( ./. ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( / ))
static member ( .- ) : lhs:FSharpNullable<'a> * rhs:'a -> FSharpNullable<'a> (requires member ( - ) and value type)
static member ( .-. ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( - ))
static member ( .* ) : lhs:FSharpNullable<'a> * rhs:'a -> FSharpNullable<'a> (requires member ( * ) and value type)
static member ( .*. ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( * ))
static member ( .+ ) : lhs:FSharpNullable<'a> * rhs:'a -> FSharpNullable<'a> (requires member ( + ) and value type)
static member ( .+. ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( + ))
static member op_Explicit : this:FSharpNullable<'T> -> 'T
static member ( <??> ) : lhs:FSharpNullable<'a> * rhs:'a -> 'a (requires value type)
static member ( -. ) : lhs:'a * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires member ( - ) and value type)
static member ( * ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( * ))
static member ( *. ) : lhs:'a * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires member ( * ) and value type)
static member ( +. ) : lhs:'a * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires member ( + ) and value type)
static member ( - ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( - ))
Full name: Script.FSharpNullable<_>
val bind : f:('a -> FSharpNullable<'b>) -> x:FSharpNullable<'a> -> FSharpNullable<'b> (requires value type and value type)
Full name: Script.FSharpNullable.bind
val f : ('a -> FSharpNullable<'b>) (requires value type and value type)
val x : FSharpNullable<'a> (requires value type)
val x' : 'a (requires value type)
Multiple items
type FSharpNullableBuilder =
new : unit -> FSharpNullableBuilder
member Bind : x:FSharpNullable<'b> * f:('b -> FSharpNullable<'c>) -> FSharpNullable<'c> (requires value type and value type)
member Return : x:'a -> FSharpNullable<'a> (requires value type)
Full name: Script.FSharpNullableBuilder
--------------------
new : unit -> FSharpNullableBuilder
member FSharpNullableBuilder.Bind : x:FSharpNullable<'b> * f:('b -> FSharpNullable<'c>) -> FSharpNullable<'c> (requires value type and value type)
Full name: Script.FSharpNullableBuilder.Bind
val x : FSharpNullable<'b> (requires value type)
val f : ('b -> FSharpNullable<'c>) (requires value type and value type)
Multiple items
module FSharpNullable
from Script
--------------------
type FSharpNullable<'T (requires value type)> =
| Value of 'T
| Null
member HasValue : bool
static member ( + ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( + ))
static member ( /. ) : lhs:'a * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires member ( / ) and value type)
static member ( / ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( / ))
static member ( ./ ) : lhs:FSharpNullable<'a> * rhs:'a -> FSharpNullable<'a> (requires member ( / ) and value type)
static member ( ./. ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( / ))
static member ( .- ) : lhs:FSharpNullable<'a> * rhs:'a -> FSharpNullable<'a> (requires member ( - ) and value type)
static member ( .-. ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( - ))
static member ( .* ) : lhs:FSharpNullable<'a> * rhs:'a -> FSharpNullable<'a> (requires member ( * ) and value type)
static member ( .*. ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( * ))
static member ( .+ ) : lhs:FSharpNullable<'a> * rhs:'a -> FSharpNullable<'a> (requires member ( + ) and value type)
static member ( .+. ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( + ))
static member op_Explicit : this:FSharpNullable<'T> -> 'T
static member ( <??> ) : lhs:FSharpNullable<'a> * rhs:'a -> 'a (requires value type)
static member ( -. ) : lhs:'a * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires member ( - ) and value type)
static member ( * ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( * ))
static member ( *. ) : lhs:'a * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires member ( * ) and value type)
static member ( +. ) : lhs:'a * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires member ( + ) and value type)
static member ( - ) : lhs:FSharpNullable<'a> * rhs:FSharpNullable<'a> -> FSharpNullable<'a> (requires value type and member ( - ))
Full name: Script.FSharpNullable<_>
val __ : FSharpNullableBuilder
member FSharpNullableBuilder.Return : x:'a -> FSharpNullable<'a> (requires value type)
Full name: Script.FSharpNullableBuilder.Return
Multiple items
type AutoOpenAttribute =
inherit Attribute
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
member Path : string
Full name: Microsoft.FSharp.Core.AutoOpenAttribute
--------------------
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
val nullable : FSharpNullableBuilder
Full name: Script.FSharpNullableComputationExpression.nullable
val private add : a:FSharpNullable<'T> -> b:FSharpNullable<'T> -> FSharpNullable<'T> (requires value type and member ( + ))
Full name: Script.FSharpNullableOps.add
val a : FSharpNullable<'T> (requires value type and member ( + ))
val b : FSharpNullable<'T> (requires value type and member ( + ))
val x : 'T (requires value type and member ( + ))
val y : 'T (requires value type and member ( + ))
val private subtract : a:FSharpNullable<'T> -> b:FSharpNullable<'T> -> FSharpNullable<'T> (requires value type and member ( - ))
Full name: Script.FSharpNullableOps.subtract
val a : FSharpNullable<'T> (requires value type and member ( - ))
val b : FSharpNullable<'T> (requires value type and member ( - ))
val x : 'T (requires value type and member ( - ))
val y : 'T (requires value type and member ( - ))
val private multiply : a:FSharpNullable<'T> -> b:FSharpNullable<'T> -> FSharpNullable<'T> (requires value type and member ( * ))
Full name: Script.FSharpNullableOps.multiply
val a : FSharpNullable<'T> (requires value type and member ( * ))
val b : FSharpNullable<'T> (requires value type and member ( * ))
val x : 'T (requires value type and member ( * ))
val y : 'T (requires value type and member ( * ))
val private divide : a:FSharpNullable<'T> -> b:FSharpNullable<'T> -> FSharpNullable<'T> (requires value type and member ( / ))
Full name: Script.FSharpNullableOps.divide
val a : FSharpNullable<'T> (requires value type and member ( / ))
val b : FSharpNullable<'T> (requires value type and member ( / ))
val x : 'T (requires value type and member ( / ))
val y : 'T (requires value type and member ( / ))
val lhs : FSharpNullable<'a> (requires value type and member ( + ))
val rhs : FSharpNullable<'a> (requires value type and member ( + ))
val lhs : 'a (requires member ( + ) and value type)
val rhs : FSharpNullable<'a> (requires member ( + ) and value type)
val lhs : FSharpNullable<'a> (requires member ( + ) and value type)
val rhs : 'a (requires member ( + ) and value type)
val lhs : FSharpNullable<'a> (requires value type and member ( - ))
val rhs : FSharpNullable<'a> (requires value type and member ( - ))
val lhs : 'a (requires member ( - ) and value type)
val rhs : FSharpNullable<'a> (requires member ( - ) and value type)
val lhs : FSharpNullable<'a> (requires member ( - ) and value type)
val rhs : 'a (requires member ( - ) and value type)
val lhs : FSharpNullable<'a> (requires value type and member ( * ))
val rhs : FSharpNullable<'a> (requires value type and member ( * ))
val lhs : 'a (requires member ( * ) and value type)
val rhs : FSharpNullable<'a> (requires member ( * ) and value type)
val lhs : FSharpNullable<'a> (requires member ( * ) and value type)
val rhs : 'a (requires member ( * ) and value type)
val lhs : FSharpNullable<'a> (requires value type and member ( / ))
val rhs : FSharpNullable<'a> (requires value type and member ( / ))
val lhs : 'a (requires member ( / ) and value type)
val rhs : FSharpNullable<'a> (requires member ( / ) and value type)
val lhs : FSharpNullable<'a> (requires member ( / ) and value type)
val rhs : 'a (requires member ( / ) and value type)
val a : FSharpNullable<int>
Full name: Script.a
val b : FSharpNullable<int>
Full name: Script.b
val c : FSharpNullable<int>
Full name: Script.c
val n : FSharpNullable<int>
Full name: Script.n
property FSharpNullable.HasValue: bool
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
Multiple items
val int64 : value:'T -> int64 (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int64
--------------------
type int64 = System.Int64
Full name: Microsoft.FSharp.Core.int64
--------------------
type int64<'Measure> = int64
Full name: Microsoft.FSharp.Core.int64<_>
More information