Null Coalescing Operator in F#? - f#

When interacting with C# libraries, I find myself wanting C#'s null coalescing operator both for Nullable structs and reference types.
Is it possible to approximate this in F# with a single overloaded operator that inlines the appropriate if case?

Yes, using some minor hackery found in this SO answer "Overload operator in F#".
At compiled time the correct overload for an usage of either ('a Nullable, 'a) ->'a or ('a when 'a:null, 'a) -> 'a for a single operator can be inlined. Even ('a option, 'a) -> 'a can be thrown in for more flexibility.
To provide closer behavior to c# operator, I've made default parameter 'a Lazy so that it's source isn't called unless the original value is null.
Example:
let value = Something.PossiblyNullReturned()
|?? lazy new SameType()
Implementation:
NullCoalesce.fs [Gist]:
//https://gist.github.com/jbtule/8477768#file-nullcoalesce-fs
type NullCoalesce =
static member Coalesce(a: 'a option, b: 'a Lazy) =
match a with
| Some a -> a
| _ -> b.Value
static member Coalesce(a: 'a Nullable, b: 'a Lazy) =
if a.HasValue then a.Value
else b.Value
static member Coalesce(a: 'a when 'a:null, b: 'a Lazy) =
match a with
| null -> b.Value
| _ -> a
let inline nullCoalesceHelper< ^t, ^a, ^b, ^c when (^t or ^a) : (static member Coalesce : ^a * ^b -> ^c)> a b =
// calling the statically inferred member
((^t or ^a) : (static member Coalesce : ^a * ^b -> ^c) (a, b))
let inline (|??) a b = nullCoalesceHelper<NullCoalesce, _, _, _> a b
Alternatively I made a library that utilizes this technique as well as computation expression for dealing with Null/Option/Nullables, called FSharp.Interop.NullOptAble
It uses the operator |?-> instead.

modified the accepted answer by jbtule to support DBNull:
//https://gist.github.com/tallpeak/7b8beacc8c273acecb5e
open System
let inline isNull value = obj.ReferenceEquals(value, null)
let inline isDBNull value = obj.ReferenceEquals(value, DBNull.Value)
type NullCoalesce =
static member Coalesce(a: 'a option, b: 'a Lazy) = match a with Some a -> a | _ -> b.Value
static member Coalesce(a: 'a Nullable, b: 'a Lazy) = if a.HasValue then a.Value else b.Value
//static member Coalesce(a: 'a when 'a:null, b: 'a Lazy) = match a with null -> b.Value | _ -> a // overridden, so removed
static member Coalesce(a: DBNull, b: 'b Lazy) = b.Value //added to support DBNull
// The following line overrides the definition for "'a when 'a:null"
static member Coalesce(a: obj, b: 'b Lazy) = if isDBNull a || isNull a then b.Value else a // support box DBNull
let inline nullCoalesceHelper< ^t, ^a, ^b, ^c when (^t or ^a) : (static member Coalesce : ^a * ^b -> ^c)> a b =
((^t or ^a) : (static member Coalesce : ^a * ^b -> ^c) (a, b))
Usage:
let inline (|??) a b = nullCoalesceHelper<NullCoalesce, _, _, _> a b
let o = box null
let x = o |?? lazy (box 2)
let y = (DBNull.Value) |?? lazy (box 3)
let z = box (DBNull.Value) |?? lazy (box 4)
let a = None |?? lazy (box 5)
let b = box None |?? lazy (box 6)
let c = (Nullable<int>() ) |?? lazy (7)
let d = box (Nullable<int>() ) |?? lazy (box 8)

I usually use defaultArg for this purpose as it is built-in to the language.

Related

Getting error FS0192: internal error: unexpected non-generation of witness when executing class definition in interactive

I have a class with minimal reproducible implementation looking like that:
type Piecewise<'U, 'V when 'U: comparison
and 'V : (static member (+): 'V * 'V -> 'V)
and 'V : (static member (*): 'V * 'V -> 'V)>
([<System.ParamArray>] pwArr: ('U * 'U * 'V) array) =
member inline this.definition = pwArr
static member inline map (mapping: 'V -> 'W) (pw: Piecewise2<'U, 'V>) =
pw.definition
|> Array.map (fun (b1, b2, v) -> b1, b2, mapping v )
|> fun x -> Piecewise x
and map member definition causes the error mentioned above when I try to commit this to F# interactive.
This class overloads (+) and (*) operators in dowstream members so I had to include them in type constraints.
If I set a weaker contraints on types for map member like that:
static member inline map (mapping: _ -> _) (pw: Piecewise<_, _>) = ...
it commits well up to map member but I'm having errors on overloads of (+) operator:
static member inline (+) (pw: Piecewise<'U, 'V>, u: 'V) =
Piecewise.map ((+) u) pw
//Polynom.fsx(120,28): warning FS0193: A type parameter is missing a constraint 'when ( ^V or ^?17597) : (static member (+) : ^V * ^?17597 -> ^?17598)'
//Polynom.fsx(120,9): error FS0071: Type constraint mismatch when applying the default type 'obj' for a type inference variable. The type 'obj' does not support the operator '+' Consider adding further type constraints
I'm using F# 6.0 in VS 17.05 on Win 10
When I calculate the value for definition field in the let binding first and then assign it to the field the class executes well:
type Piecewise<'U, 'V when 'U: comparison
and 'V : (static member (+): 'V * 'V -> 'V)
and 'V : (static member (*): 'V * 'V -> 'V)>
([<System.ParamArray>] pwArr: ('U * 'U * 'V) array) =
let definition' =
pwArr
|> Array.map (fun (b1, b2, v) ->
if b1 > b2 then b2, b1, v else b1, b2, v )
|> Array.sortBy (fun (b1, _, _) -> b1)
member inline this.definition =
definition'
member inline this.Evaluate(u: 'U) =
this.definition
|> Array.choose(fun (b1, b2, v) ->
if b1 <= u && u < b2 then Some v else None
)
static member inline map (mapping: 'V -> 'W) (pw: Piecewise<'U, 'V>) =
pw.definition
|> Array.map (fun (b1, b2, v) -> b1, b2, mapping v )
|> fun x -> Piecewise x
Still don't really understanding why this works while the direct assignment doesn't

Can someone explain these F# type inference oddities?

I'm experiencing a lot of unexplained behavior with the type inference of F# (or lack of inference rather).
I would expect that all the value functions below would return the correct type T given a Foo of T but in several cases it returns an obj.
type Foo<'T>(v:'T) =
member __.Value = v // 'T
static member (~~) (foo:Foo<_>) = foo.Value // Foo<'a> -> 'a
// should know the type but not always!
~~(Foo 1) // int
let value (u:Foo<_>) = u.Value // Foo<'a> -> 'a
let value (u:Foo<_>) = ~~u // Foo<obj> -> obj
let inline value (u:Foo<_>) = ~~u // Foo< ^a> -> ^a
let (~~) (foo:Foo<_>) = (Foo<_>.(~~))foo // Foo<'a> -> 'a
let value (u:Foo<_>) = ~~u // Foo<'a> -> 'a
let inline (~~) (x:^a) : ^b =
(^a : (static member (~~) : ^a -> ^b) x) // ^a -> ^b
let value (u:Foo<_>) = ~~u // Foo<obj> -> obj
let inline (~~) (x:^a) : 'b =
(^a : (static member (~~) : ^a -> 'b) x) // ^a -> 'b
let value (u:Foo<_>) = ~~u // Foo<'a> -> 'a
What is going on??
I cannot tell why certain functions involving an invocation of your op_TwiddleTwiddle operator definitions cannot be generalized. On the other hand, there are definitively interesting things happening here. Let's start by bringing the code into a form that avoid redefinitions of top-level bindings:
type Foo<'T>(v:'T) =
member __.Value = v // 'T
static member (~~) (foo:Foo<_>) = foo.Value // Foo<'a> -> 'a
module M1 =
let value (u:Foo<_>) = ~~u // Foo<obj> -> obj
module M2 =
let inline value (u:Foo<_>) = ~~u // Foo< ^a> -> ^a
module M3 =
let (~~) (foo:Foo<_>) = (Foo<_>.(~~))foo // Foo<'a> -> 'a
let value (u:Foo<_>) = ~~u // Foo<'a> -> 'a
module M4 =
let inline (~~) (x:^a) : ^b =
(^a : (static member (~~) : ^a -> ^b) x) // ^a -> ^b
let value (u:Foo<_>) = ~~u // Foo<obj> -> obj
module M5 =
let inline (~~) (x:^a) : 'b =
(^a : (static member (~~) : ^a -> 'b) x) // ^a -> 'b
let value (u:Foo<_>) = ~~u // Foo<'a> -> 'a
Looking at the compiled form of the Foo<'T> type, it is clear that the operator takes a type parameter for its return type:
public class Foo<T>
{
internal T v;
public T Value
{
get
{
return this.v;
}
}
public Foo(T v) : this()
{
this.v = v;
}
public static a op_TwiddleTwiddle<a>(Foo<a> foo)
{
return foo.v;
}
}
This is immaterial as none of the examples except the M2 inline definition do actually call the op_TwiddleTwiddle operator. All the other examples are optimized by direct access to the backing field of the Value property, albeit we would expect it to be transparent, not influencing generalization.
The other interesting cases are
M3, where annotation of the operator Foo<_>.(~~) improves the generalization, and
M5, in that elimination of the second (unnecessary) statically resolved type variable also makes it work better.

Object Expression as Computation Builder

Given a generic interface declaration like
type IFoo<'T,'MT> =
abstract Return : 'T -> 'MT
abstract Bind : 'MT * ('T -> 'MT) -> 'MT
it's actually possible to use object expressions as computation builder expressions, which could provide for an interesting approach to the division between encapsulation and execution logic of monadic workflows.
let inline addOption mx my =
{ new IFoo<_,_> with
member __.Return x = Some x
member __.Bind(ma, f) = Option.bind f ma }
{ let! x = mx
let! y = my
return x + y }
// val inline addOption :
// mx: ^a option -> my: ^a option -> ^a option
// when ^a : (static member ( + ) : ^a * ^a -> ^a)
addOption (Some 1) (Some 2)
// val it : int option = Some 3
addOption None (Some 2)
// val it : int option = None
The compiler checks on the type of the expression if the expected methods are present. But it is only halfway there; because for real monads, I would need to get the method signature abstract Bind : 'MT * ('T -> 'MU) -> 'MU honoured, a projection to a different non-encapsulated type. Why can't this be done?

F# pattern match using type constraints

Is it possible to do an F# type test pattern with a member constraint?
Such as:
let f x =
match x with
| :? (^T when ^T : (static member IsInfinity : ^T -> bool)) as z -> Some z
| _ -> None
or
let g x =
match x with
| (z : ^T when ^T : (static member IsInfinity : ^T -> bool)) -> Some z
| _ -> None
Neither which work.
You cannot do this, as Petr said, statically resolved type parameters are resolved at compile time. They're actually a feature of the F# compiler rather than being a .NET feature, hence why this kind of information isn't available at runtime.
If you wish to check this at runtime, you could use reflection.
let hasIsInfinity (x : 'a) =
typeof<'a>.GetMethod("IsInfinity", [|typeof<'a>|])
|> Option.ofObj
|> Option.exists (fun mi -> mi.ReturnType = typeof<bool> && mi.IsStatic)
This will check for a static method called IsInfinity with type sig: 'a -> bool

A shorter type constraint for F#

I'm practicing with F# and I've though of implementing a type-constrained compare function for F#. In C#, it's implemented by this
// in C#
static int cmp<T>(T x, T y) where T: System.IComparable<T>
{
return x.CompareTo(y);
}
However, in F#, the best way I've come up is this.
(* in F# *)
let cmp (x: 'a when 'a :> 'a System.IComparable) (y: 'a when 'a :> 'a System.IComparable)
= x.CompareTo(y)
I tried the one below but it didn't work
let cmp (x: 'a) (y: 'a) when 'a :> 'a System.IComparable
= x.CompareTo(y)
Is my working F# sample the shortest way or is there another?
Another (cleaner, IMO) way to implement this is by adding an explicit generic type parameter to the function, like this:
let cmp<'T when 'T :> System.IComparable<'T>> (x : 'T) (y : 'T) =
x.CompareTo y
Ok, found it. I was browsing through the examples in MSDN's F# type constraint and at the thrid from the last example, I found this
let inline add(value1 : ^T when ^T : (static member (+) : ^T * ^T -> ^T), value2: ^T) =
value1 + value2
I notice that constraint for ^T in value1 is used in value2, so I change my cmp function to this
let cmp (x: 'a when 'a :> 'a System.IComparable) (y: 'a) = x.CompareTo(y)
I ran through the fsi and got the same type signature
> let cmp (x: 'a when 'a :> 'a System.IComparable) (y: 'a) = x.CompareTo(y);;
val cmp : 'a -> 'a -> int when 'a :> System.IComparable<'a>
> let cmp (x: 'a when 'a :> 'a System.IComparable) (y: 'a when 'a :> 'a System.IComparable) = x.CompareTo(y);;
val cmp : 'a -> 'a -> int when 'a :> System.IComparable<'a>

Resources