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.
map function, found in many functional programming languages, is one example of a higher-order function. It takes as arguments a function f and a collection of elements, and as the result, returns a new collection with f applied to each element from the collection.
A function that takes another function as one of its arguments, as every does, is called a higher-order function. If we focus our attention on procedures, the mechanism through which Scheme computes functions, we think of every as a procedure that takes another procedure as an argument—a higher-order procedure.
Higher-Order Functions(HoF) and Callback Functions(CB) are different. Higher-Order Functions(HoF): A function that takes another function(s) as an argument(s) and/or returns a function as a value. Callback Functions(CB): A function that is passed to another function.
High-Order functions are simply functions that accept functions as arguments and/or return functions as a result. I have used higher-order functions since the 1990s in C++ along with the Standard Template Library. That practice continued with ActionScript development in Flash/Flex, and more recently in TypeScript.
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>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With