Lamba vs. standard Functions Summary
Lambdas are simply what C# and Java call
first class functions.For historical reasons neither Java or C# treat standard functions as first class ones; however they can fairly easily be linked to Lambda syntax. "First class" simply means that functions are treated no different to variables, which means that we can :
- pass a function as arguments to other functions
- return a function as a value from other functions
- assign a function to variable
- store functions in a data structure e.g. List
There are 3 major delegate types that are used to define a Lambda:
- Action: a function that returns void
- Func: a function that returns a value, e.g. int, string, ...
- Predicate: a function that returns a bool
Action function comparison (same functionality):
PHP:
// C# standard function
static void Print(string message)
{
Console.WriteLine(message);
}
// C# lambda function
static Action<string> Print1 = message => {
Console.WriteLine(message);
};
// C# lambda shorter version
static Action<string> Print2 = message => Console.WriteLine(message);
Action function usage example (same functionality):
PHP:
Print("Hello"); // Hello
Print1("Hello1"); // Hello1
Print2("Hello2"); // Hello2
Func(value) function comparison (same functionality):
PHP:
// C# standard function
static string Hello(string message)
{
return "Hello, " + message;
}
// C# lambda function
static Func<string, string> Hello1 = message => {
return "Hello, " + message;
};
// C# lambda shorter version
static Func<string, string> Hello2 = message => "Hello, " + message;
Func(value) function usage example:
PHP:
Console.WriteLine(Hello("World")); // Hello, World
Console.WriteLine(Hello1("World1")); // Hello, World1
Console.WriteLine(Hello2("World2")); // Hello, World2
Predicate(bool) function comparison (same functionality):
PHP:
// C# standard function
static bool IsEven(int value)
{
return value % 2 == 0;
}
// C# lambda function
static Predicate<int> IsEven1 = value => {
return value % 2 == 0;
};
// C# lambda shorter version
static Predicate<int> IsEven2 = value => value % 2 == 0;
// Using Func, instead of Predicate
static Func<int, bool> IsEven3 = value => value % 2 == 0;
Predicate(bool) function usage example:
PHP:
Console.WriteLine(IsEven(14)); // true
Console.WriteLine(IsEven1(14)); // true
Console.WriteLine(IsEven2(14)); // true
Console.WriteLine(IsEven3(14)); // true
C# Delegate Inconsistency
Whilst we can define a Predicate with the Func delegate we cannot define an Action (void); this e.g. will not work, because for some reason C# classifies
void differently from the other types . :wtf:
PHP:
static Func<string, void> Print3 = message => Console.WriteLine(message);
Function composition example, using a List and Extension Methods:
Here's an example of first class functions in a List:
PHP:
var list = new List<Func<double, double>>() { Math.Log, Math.Cos, Math.Sin, Math.Tan };
Then to compose a result from this I can e.g. define a Compose extension method on IEnumerable:
PHP:
public static T Identity<T>(T value) => value;
public static Func<T, T> Compose<T>(Func<T, T> function1, Func<T, T> function2)
=> arg1 => function2(function1(arg1));
public static Func<T, T> Compose<T>(this IEnumerable<Func<T, T>> elements)
=> elements.Aggregate<Func<T, T>, Func<T, T>>(Identity<T>, Compose<T>);
This then allows me call it up on the 'list' we defined:
PHP:
Console.WriteLine(list.Compose()(10)); // -0,713268027987389
This is basically the same as this:
PHP:
Console.WriteLine(Math.Tan(Math.Sin(Math.Cos(Math.Log(10))))); // -0,713268027987389
...basically our extensions methods created this function composition, by using
Linq Aggregate, with an initial value of the
Identity function, and the
Compose function for the aggregation.