Converting System.Func to FSharpFunc

Interop of delegate style types between F# and other .Net languages is a pain point that results from a fundamental difference in how delegates are represented in the F# language.  Typical .Net languages like C# see a delegate as taking 0 to N parameters and potentially returning a value.  F# represents all exposed delegates as taking and returning a single value via the FSharpFunc<T,TResult> type.  Multiple parameters are expressed by having the TResult type be yet another FSharpFunc<T,TResult>.

This creates a host of problems calling exposed F# delegate / function types

  • Can’t use C# lambda expressions which take more than one parameter
  • System.Func<> expressions of equivalent logical shape can’t be converted
  • Method group conversions don’t work

The only step is to introduce a conversion step when calling into F# code.  F# does provide a helper method in F# in the FSharpFunc.FromConverter method.  But once again it’s only useful for delegates of one parameter, anything higher requires a more in depth conversion.  For example here is the C# code to convert a 2 parameter delegate into the equivalent F# type. 

 public static FSharpFunc<T1, FSharpFunc<T2,TResult>> Create<T1, T2, TResult>(Func<T1,T2,TResult> func)
{
    Converter<T1, FSharpFunc<T2, TResult>> conv = value1 =>
        {
            return Create<T2,TResult>(value2 => func(value1, value2));
        };
    return FSharpFunc<T1, FSharpFunc<T2, TResult>>.FromConverter(conv);
}

Not very pretty or intuitive because the code needs to recreate the nested style of F# func’s.  This gets even more tedious and error prone as it gets past 2 parameters.

The simplest solution, as is true with most F# interop scenarios, is to leverage F# itself to define the interop / conversion layer.  It already naturally creates the proper nesting structure so why spend type redoing the logic in C#.  The logic can then be exposed as a set of factory and extension methods to make it easily usable from C#. 

 [<Extension>]
type public FSharpFuncUtil = 

    [<Extension>] 
    static member ToFSharpFunc<'a,'b> (func:System.Converter<'a,'b>) = fun x -> func.Invoke(x)

    [<Extension>] 
    static member ToFSharpFunc<'a,'b> (func:System.Func<'a,'b>) = fun x -> func.Invoke(x)

    [<Extension>] 
    static member ToFSharpFunc<'a,'b,'c> (func:System.Func<'a,'b,'c>) = fun x y -> func.Invoke(x,y)

    [<Extension>] 
    static member ToFSharpFunc<'a,'b,'c,'d> (func:System.Func<'a,'b,'c,'d>) = fun x y z -> func.Invoke(x,y,z)

    static member Create<'a,'b> (func:System.Func<'a,'b>) = FSharpFuncUtil.ToFSharpFunc func

    static member Create<'a,'b,'c> (func:System.Func<'a,'b,'c>) = FSharpFuncUtil.ToFSharpFunc func

    static member Create<'a,'b,'c,'d> (func:System.Func<'a,'b,'c,'d>) = FSharpFuncUtil.ToFSharpFunc func

Now I  can convert instances of System.Func<> to the F# equivalent by simply calling .ToFSharpFunc().

 var cmd = Command.NewSimpleCommand(
    name,
    flagsRaw,
    func.ToFSharpFunc());

Much better.