Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call F# function from C# passing function as a parameter

Tags:

c#

f#

I have the following F# function

let Fetch logger id = 
    logger "string1" "string2"
    // search a database with the id and return a result

In my C# class I want to call the Fetch F# function mocking out the logger function. So I have the following C# function as the mocker.

void Print(string x, string y) { // do nothing }

I'm trying to call the F# function from a C# class with the following.

var _logger = FuncConvert.ToFSharpFunc<string, string>(Print);
var _result = Fetch(logger, 3);

The problem with FuncConvert.ToFSharpFunc is that takes only one type argument. When I change the Fetch F# logger function to the following it works fine when I use ToFSharpFunc(Print) where the C# Print function also takes in one string.

let Fetch logger id = 
    logger "string1"
    // search a database with the id and return a result

Anyone got ideas?

like image 525
Shane Fleming Avatar asked Mar 23 '18 12:03

Shane Fleming


People also ask

How do you use called for?

call for somethingto publicly ask for something to happen They called for the immediate release of the hostages. The opposition party has called for him to resign.

What does the phrase call for mean?

phrasal verb. If you call for something, you demand that it should happen. They angrily called for Robinson's resignation. [

What do you call someone who will do anything for money?

Definitions of avaricious. adjective. immoderately desirous of acquiring e.g. wealth. “they are avaricious and will do anything for money” synonyms: covetous, grabby, grasping, greedy, prehensile acquisitive.


1 Answers

Short Version

var tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(t=>Print(t.Item1,t.Item2));
var logger = FuncConvert.FuncFromTupled(tupleLogger);

MyOtheProject.MyModule.Fetch(logger, 3);

Long Version

F# functions only accept one argument. Multiple arguments essentially create nested functions. You need to do the same on C#'s side.

Check the type of the logger parameter in C# with Intellisense. It's

Microsoft.FSharp.Core.FSharpFunc<string, Microsoft.FSharp.Core.FSharpFunc<string, a>>

FuncConvert.ToFSharpFunc can't create this. FuncFromTupled though can create this from an FSharpFunc that takes a Tuple with multiple fields as an argument.

That's something that can be created by ToFsharpFunc :

FSharpFunc<Tuple<string,string>,Unit> tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(
       t=> Print(t.Item1,t.Item2));

or

var tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(t=> Print(t.Item1,t.Item2));

As FuncFromTupled's description says, it's A utility function to convert function values from tupled to curried form.. tupleLogger is a tupled form that we need to convert to a curried form:

var logger = FuncConvert.FuncFromTupled(tupleLogger);

The resulting code looks like:

var tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(t=>Print(t.Item1,t.Item2));
var logger = FuncConvert.FuncFromTupled(tupleLogger);

MyOtheProject.MyModule.Fetch(logger, 3);

You could create a utility function to combine the two conversions :

public static class MyFuncConvert
{
    public static FSharpFunc<T1, FSharpFunc<T2, Unit>> ToFSharpFunc<T1, T2>(Action<T1, T2> action)
    {
        var tupled = FuncConvert.ToFSharpFunc<Tuple<T1, T2>>(
                                  t => action(t.Item1, t.Item2));
        var curried = FuncConvert.FuncFromTupled(tupled);
        return curried;
    }
}

Which would allow you to write :

var logger = MyFuncConvert.ToFSharpFunc<string,string>(Print);
like image 106
Panagiotis Kanavos Avatar answered Oct 18 '22 13:10

Panagiotis Kanavos