Έχουν δημοσιευτεί Κυριακή, 6 Απριλίου 2014 6:51 μμ από το μέλος k badas

L stands for lambda

Lambda expressions are anonymous functions that can be really helpful at times. Alike many other .NET methods, lambda expressions are not the only way to create the algorithm you want, however they may help you in writing code that is much easier to read than the old fashioned way. We are going to see what lambda expressions are and go through some basic applications.
 
Lambda calculus
 
Even though the fact that you reading this article shows that you are interested in the .NET's lambda part, we'll first take a little tour over its mathematical background. When Microsoft developers released .Net 3.5 and introduced lambda expressions, that idea had been in store for a long time. The following description is nothing more but a naive description of the mathematical model and will be used as an introduction to the development model.
In 1930s Church, a mathematician, in order to strengthen the foundations of mathematics, created a formal mathematical system based on function abstraction. He called that system lambda calculus and used the Greek letter λ as its symbol.
 
This λ-calculus system was based on anonymous functions. Till then the usual way to create a function was for example f(x) = x * x.
λ-calculus suggests that the function's name (f in the previous example) is unnecessary. Instead we could use λx.x*x. Such an expression is no longer a function but is rather called lambda abstraction.
A lambda abstraction has the form λ<arguments>.<function body>
 
By the way, why did Church name his system after the Greek letter λ? Similar attempts so far used the notation. Church, creating a new system, wished it to be similar, yet different from the existing ones. So he moved the symbol left, like that Λx.x *x. This reminded him of the capital Greek letter lambda (Λ), thus the name was created. Later on the the symbol was turned to λ (λx.x*x), the lowercase Greek letter, as the current typewriters had a hard time printing.
 
A lambda abstraction represents a function. The function λx.x*x represents is x->x*x.
In the same way we have <parameters> -> <function body>.
 
This is the way .NET treats its lambda expressions as we are soon about to see. A lambda expression is the equivalent of a lambda abstraction. So, as we stated in the beginning, we end up that a lambda expression is nothing more but an anonymous function. A function that has no name, does not exist in code and is created on the fly in order for us to use it.
 
lambda-calculus
 
This is a lambda expression
 
We talked about delegates stating that its similar to method pointers in an older article. Using a delegate we can write the following code.
 
delegate int intDelegate(int i);
    //Create anonymous method
    private int DelegateSquare()
    {
        intDelegate d = delegate(int i){return i = i * i;};
        return d(2);
    }
This method will return 4.
 
Since lambda expressions are nothing more but anonymous functions we can write the same code as
    //Create anonymous method using lambda expression
    private int LambdaSquare()
    {
        intDelegate d = i => i * i;
        return d(2);
    }
 
Here's the difference: Instead of delegate(int i){return i = i * i;}; we get i => i * i;
 
We can tell there's no actual difference in what the result will be. The result will still be 4. What we have accomplished is we have turned a simple anonymous method into an even simpler lambda expression.
 
Using λ-calculus we have λx.x*x or x->x*x. Using lambda expressions we have i => i * i. It's all about the same thing, we create an anonymous function that gets the i parameter and returns i * i.
 
If we wanted to create lambda expressions that looked more like anonymous functions we could use brackets. The previous example would then become
 
    //Create anonymous method using lambda expression
    intDelegate LambdaSquare()
    {
        intDelegate d = i => { return i* i; };
        return d(2);
    }
 
Supposing we wanted to create lambda expressions having more than one argument, we would have to present the arguments within parenthesis like this
 
   delegate int twoIntDelegate(int i);
    //Lambda expression accepting more than one argument
    private int LambdaMultiply()
    {
        twoIntDelegated = (i, j) => i * j;
        return d(2,3);
    }
 
Actually all lambda expressions are supposed to contain arguments within parenthesis, however in case of one argument it is not compulsory. So most developers prefer writing i => i * i instead of (i) => i * i, even though it's quite the same thing.
 
Now, here's a bit more complex example that can show us how helpful lambda expressions can be.
 
This method will return the maximum number from a list of integers that is also greater than the minValue specified.
 
//Old fashioned code
    private int GetMaxIntValueGreaterThanLocalInteger()
    {
        List<int> intList = new List<int> { 1, 2, 3, 4, 5 };
        int minValue = 5;
        int maxValue = -1;
         foreach (int i int intList)
           if ((i > minValue) && (i > maxValue))
                maxValue = i;
         return maxValue;
    }
 
This example returns -1 since there is no integer greater than 5 inside the intList.
Here's the equivalent code using a modern approach.
 
    //Modern code
    private int GetMaxIntValueGreaterThanLocalIntegerLambda()
    {
        List<int> intList = new List<int> { 1, 2, 3, 4, 5 };
        intminValue = 3;
 
        //Get the integers greater than minValue
        var minValueLambda = intList.Where(i => i > minValue);
        //Check if at least one integer was greater than minValue
        if (minValueLambda.Any())
            //Return maximum integer
            return minValueLambda.Max();
        else
            return -1;
    }
 
This time the result will be 5.
First we use the lambda expression i => i > minValue to remove the integers that are less than minValue. Then we simply check if there are possible results using Any() and get the maximum result using Max().
 
Here's what Visual Studio's IntelliSense proposes we should use as an argument to the Where method - Func(int, bool) predicate. Predicate stands for anonymous methods that use boolean expressions testing each element of the given sequence. Since we can use anonymous methods we can also use lambda expressions. There are quite a lot of methods that can accept such arguments. The previous example could as well have been written as
 
    private int GetMaxIntValueGreaterThanLocalIntegerLambdaAny()
    {
        List<int> intList = new List<int> { 1, 2, 3, 4, 5 };
        int minValue = 3;
 
        //Get the integers that are greater than minValue
        if (intList.Any(i => i > minValue))
            //Return maximum integer
            return intList.Max();
        else
            return -1;
 
    }
 
Instead of predicates there are also selector expressions which can modify the return value.
Supposing we wanted to get the square of the previous method's return value. Max method can get lambda expression argument. We can write
 
    private int  GetSquareMaxIntValueGreaterThanLocalInteger()
    {
        List<int> intList = new List<int> { 1, 2, 3, 4, 5 };
        int minValue = 3;
 
        //Get the integers that are greater than minValue
        if (intList.Any(i => i > minValue))
            //Return square of maximum integer
            return intList.Max(i => i * i);
        else
            return -1;
 
    }
 
 
Lambda expressions and anonymous methods.
 
So far we have talked about anonymous methods and lambda expressions and it seems that they have many things in common. Actually, we could say that lambda expressions are kind of a special category of anonymous methods. The reason to prefer lambda expressions to anonymous functions is that they are easier to be used by a developer. I have even met novice developers who where familiar with the Where method but knew nothing concerning lambda expressions, delegates or anonymous functions.
 
Keep in mind these simple expressions we created earlier
Anonymous method  delegate(int i){return i = i * i;};
Lambda expression   i => i * i;
 
This lambda expression can also be written this way
(int i) => { return i * i; };
which makes it similar to the method.
 
You can now see all the things we can omit (if possible) when using lambda expressions.
1) parameter type declaration
2) parenthesis between parameter
3) brackets between body declaration
4) the return keyword
 
Ending up in the much simpler expression i => i * i;
 
As we mentioned, when using lambda expressions you do not have to pay attention to parameter types. Even though the anonymous method explicitly states that i is an integer, the lambda expression does not. Lambda expressions use type inference, that is .NET will deduct what type the variable should be and make things easier for you. If however you feel like this will make things worse, stick with the anonymous method.
 
lambda l
 
Conclusion
 
Lambda expressions, similar to anonymous methods allow you to write simple and easy to read code. We have mentioned the basic points of how they work and why we should use them.

 

 

Reference DotNetHints
Share


Σχόλια:

Χωρίς Σχόλια