Complement higher order function

OliverRadini

I'm trying to write a complement function, such that when provided with a function f, it returns a function which, when provided with the same input as f, returns it's logical opposite.

Having put similar code into VS2017, I get no errors, however I'm not yet able to run the code to see if it'll work as expected. My intention was to try this in a repl first, to see if it would do as expected. The code I used there was this:

   public static Func<T, bool> Complement<T>(Func<T, bool> f)
   {
       return (T x) => !f(x);
   }

   public static bool GreaterThanTwo (int x) {
     return x > 2;
   }

   static public void Main(string[] args)
   {
     Func<int, bool> NotGreaterThanTwo = Complement(GreaterThanTwo);
     Console.WriteLine(NotGreaterThanTwo(1));
   }

Here is a link to the same.

Within the repl, I get the error:

main.cs(17,42): error CS0411: The type arguments for method `MainClass.Complement(System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly Compilation failed: 1 error(s), 0 warnings compiler exit status 1

I have looked at a few questions on stack overflow which cover the same error message, for instance this and this, but I'm not able to see how they relate to this issue I'm having.

Panagiotis Kanavos

Complement(GreaterThanTwo) is trying to use a method group, not a Func<int,bool> delegate. This fails because Complement<T> expects a generic delegate.

The call would compile with a Func<int,bool>, eg :

Func<int,bool> cmp= x=>x > 2;
var NotGreaterThanTwo = Complement(cmp);

There's an implicit conversion from method groups to delegates which means this works too :

Func<int,bool> cmp= GreaterThanTwo;
var NotGreaterThanTwo = Complement(cmp);

Which raises the question why didn't the original code work? An explicit cast also works:

var NotGreaterThanTwo = Complement((Func<int,bool>)GreaterThanTwo);

A method group represents a group of overloaded methods, not just a single method. This means that the compiler has to be able to find which of the available groups to use in any situation.

The rest is supposition as I haven't found a definite reference or design note about this specific case.

The first two method group conversion rules probably explains what's wrong :

  • A single method M is selected corresponding to a method invocation (Method invocations) of the form E(A), with the following modifications:

    • The argument list A is a list of expressions, each classified as a variable and with the type and modifier (ref or out) of the corresponding parameter in the formal_parameter_list of D.
    • The candidate methods considered are only those methods that are applicable in their normal form (Applicable function member), not those applicable only in their expanded form.
  • If the algorithm of Method invocations produces an error, then a compile-time error occurs. Otherwise the algorithm produces a single best method M having the same number of parameters as D and the conversion is considered to exist.

In Complement<T>(Func<T, bool> f) there's no invocation, so the compiler doesn't know which method in the group to pick and convert. It doesn't even know what T is, so it can't know if any of the methods in that group match.

On the other hand this works :

var xx=new []{1,2,3}.Where(GreaterThanTwo);

In this case though, Where's signature is :

public static System.Collections.Generic.IEnumerable<TSource> Where<TSource> (
    this System.Collections.Generic.IEnumerable<TSource> source, 
    Func<TSource,bool> predicate);

and the type argument is already available from IEnumerable<TSource>.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related