Search code examples
f#interop

How do I construct a Func for the overload of String.Equals which accepts two parameters?


I'm messing around with C# function conversion in F#. I know there are more idiomatic ways to do this (including using the static methods on System.String), but this is a learning exercise. In C#, if I want to create a predicate based on an instance method of an object, it's straightforward

var predicate = MakeEquals("hello");
Console.WriteLine(predicate("HELLO", StringComparison.OrdinalIgnoreCase)); // True

Func<string, StringComparison, bool> MakeEquals(string s) => s.Equals;

In F#, this doesn't compile:

let makeEquals (s: string) : string -> StringComparison -> bool =
    let f = Func<string, StringComparison, bool>(s.Equals)
    FuncConvert.FromFunc(f)
error FS0001: This expression was expected to have type    
    'StringComparison -> bool'    
but here has type  
    'bool'

This error confuses me, especially since this works:

let makeEquals (s: string) : string -> bool =
    let f = Func<string, bool>(s.Equals)
    FuncConvert.FromFunc(f)

And I have no trouble calling the overloaded method

"hello".Equals("HELLO", StringComparison.OrdinalIgnoreCase) // true

What am I doing wrong?


Solution

  • The type of that overload of s.Equals is actually string * StringComparison -> bool, not string -> StringComparison -> bool. That is, from F# point of view, the overload accepts a single argument that is a tuple, not two arguments.

    So this would work:

    Func<string * StringComparison, bool>(s.Equals)
    

    Or you can use a wrapper function for currying it:

    Func<string, StringComparison, bool>(fun a b -> s.Equals(a, b))