FSharpPlus divRem – how does it work?

  • A+
Category:Languages

Looking at FSharpPlus I was thinking to how to create a generic function to be used in

let qr0  = divRem 7  3 let qr1  = divRem 7I 3I let qr2  = divRem 7. 3. 

and came out with a possible (working) solution

let inline divRem (D:^T) (d:^T): ^T * ^T = let q = D / d in q,  D - q * d 

then I looked at how FSharpPlus implemented it and I found:

open System.Runtime.InteropServices  type Default6 = class end type Default5 = class inherit Default6 end type Default4 = class inherit Default5 end type Default3 = class inherit Default4 end type Default2 = class inherit Default3 end type Default1 = class inherit Default2 end  type DivRem =     inherit Default1     static member inline DivRem (x:^t when ^t: null and ^t: struct, y:^t, _thisClass:DivRem) = (x, y)     static member inline DivRem (D:'T, d:'T, [<Optional>]_impl:Default1) = let q = D / d in q,  D - q * d     static member inline DivRem (D:'T, d:'T, [<Optional>]_impl:DivRem  ) =         let mutable r = Unchecked.defaultof<'T>         (^T: (static member DivRem: _ * _ -> _ -> _) (D, d, &r)), r      static member inline Invoke (D:'T) (d:'T) :'T*'T =         let inline call_3 (a:^a, b:^b, c:^c) = ((^a or ^b or ^c) : (static member DivRem: _*_*_ -> _) b, c, a)         let inline call (a:'a, b:'b, c:'c) = call_3 (a, b, c)         call (Unchecked.defaultof<DivRem>, D, d)      let inline divRem (D:'T) (d:'T) :'T*'T = DivRem.Invoke D d 

I am sure that there are good reasons to make it as such; however I am not interested in why it's been done like that, but:

How does this work?

Is there any documentation helping to understand how this syntax works, especially the three DivRem static method overloads?

 


Your implementation is just fine, it's actually the same as the 2nd overload, which correspond to the default implementation.

F#+ is an F# base library, similar to F# core, and it also uses a fallback mechanism. F# core uses static optimizations and fakes some type constraints in a non-safe way, but this technique is not possible outside the F# compiler project, so F#+ achieve the same effect with a trait call to an overloaded method, without need to fake static constraints.

So, the only difference between your implementation and the one in F#+ is that F#+ will first look (at compile-time) for a DivRem static member defined in the class of the numeric type being used, with a standard .NET signature (using a return value and a reference, instead of a tuple) which is 3rd overload. This method could have an optimized, specific implementation. I mean, it is assumed that if this method exists it will be at worst equally optimal than the default definition.

If this method does not exists, it will fallback to the default definition, which as I said it's the 2nd overload.

The 1st overload will never match and it's there only to create the necessary ambiguity in the overload set.

This technique, is not well documented at the moment, as the example in the docs from Microsoft is a bit unfortunate since it doesn't really work. Probably because it doesn't have enough ambiguity.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: