Can someone explain how this code works in F#:
https://github.com/fsprojects/FSharpPlus/blob/master/src/FSharpPlus/Control/Functor.fs#L99-99
static member inline Invoke (mapping: 'T->'U) (source: '``Functor<'T>``) : '``Functor<'U>`` =
let inline call (mthd: ^M, source: ^I, _output: ^R) = ((^M or ^I or ^R) : (static member Map : (_*_)*_ -> _) (source, mapping), mthd)
call (Unchecked.defaultof<Map>, source, Unchecked.defaultof<'``Functor<'U>``>)
Specifically the call function, which uses a syntax which I do not understand
e.g.
- What does
(^M or ^I or ^R)mean? - What parts of this are code and what parts are type definitions?
- How does it have a type signature
... -> 'awhen it seems to return a tuple? - Is there some kind of type level programing hackery going on?
This voodoo syntax is called "Statically Resolved Type Parameters", or SRTPs for short.
Normal type parameters are denoted with a tick, like
'a. These type parameters are natively supported by the .NET runtime, so types and functions with such type parameters are compiled directly to classes and methods in IL.SRTPs are denoted with a circumflex, like
^M, and are not supported by the .NET runtime, and therefore cannot be compiled to IL, and therefore have to be "unrolled" during compilation time. This means that for every use site of thus parametrized function, the compiler must determine what concrete types the SRTPs should be, and insert the whole body of the function at call site, also known as "inlining". This is what theinlinekeyword is for.The point of SRTPs is to express a constraint saying "any type that has a method or property with this signature". In your particular example, this is expressed on this line:
The line means:
call,^M,^I, and^Rrespectively,Map,(^I * ^R) * ^M,((source, mapping), mthd)as parameter.As to why it returns a tuple - it doesn't. The tuple on the last line is not returned from the
Invokefunction, but passed as parameter to thecallfunction. It's the result ofcallthat is returned fromInvoke.