Lambda Expressions
From The Oxygene Language Wiki
This is a Language topic
Feel free to add your notes to this topic below.
What Are Lambda Expressions?
Lambda expressions are a special type of expression that can be best thought of as mapping a set of one or more values to a result, using a function. Lambda expressions are most notable used with the Query Operators that form the basis of Query Expressions, but can technically be used wherever a matching delegate of future is expected.
The discussion of lambda expressions is perhaps best started with an example, so the following code shows a lambda expression used with the "Where" method introduced by LINQ:
var MyCustomers: sequence of Customer; //... MyCustomers.Where(c -> c.Name = 'Smith');
As you can see, the lambda expression consists of an input variable (or possibly several input variables grouped by using parenthesis), the "->" operator and an expression that typically uses the input variables to calculate the result.
Technically speaking, the lambda expression defines an anonymous method, so
c -> c.Name = 'Smith'
could be considered a shortcut for writing
method (c: type1): type2; begin result := c.Name = 'Smith'; end;
where the type of "c" (type1) and of the result (type2) are inferred from the context, in this case, "MyCustomers.Where" expects a delegate where the input is a Customer and the result is a Boolean.
When used with the Query Operators, lambda expressions have several advantages over passing an anonymous method or a normal delegate (though both of these options are of course available):
- Firstly, Lambda Expressions are much more concise, and work better "inline", especially when concatenating several Standard Query Operators in the same statement.
- Secondly, as stated above, types are automatically inferred by the compiler based on the context (usually the type of sequence the SQL is being applied to).
Most importantly though, depending on the context and the used SQL, lambda expressions can either be compiled to managed code like the rest of your application, or can be translated into so called Expression Trees, for remote execution.
Using Lambda Expressions In Delphi Prism
Lambda expressions are extremely useful when working with the standard query operators in LINQ:
var myList := new List<Person>; myList.Add(new Person(Name := 'Albert', Age := 32)); myList.Add(new Person(Name := 'Chris', Age := 26)); //... var youngOnes := myList.Where(p -> p.Age < 30); //sequence of people younger than 30
Delphi Prism will infer the type of the parameter from the delegate that is expected at this place. Of course you can have lambdas returning something else than a boolean:
var nameAndAge := myList.Select(p -> p.Name+' ('+p.Age.ToString+')'); //e.g. "Albert (32)"
Delphi Prism infers the return type and creates a String, in this case Select, in turn, then return a sequence of String.
Lambda expressions don't have to return a result at all, they can also be used as actions:
var printOut : Action<String> := s -> Console.WriteLine(s); printOut('foo');
Parameter-less Lambda Expressions
Delphi Prism supports lambda expressions without parameters, simply by omitting the operand to the left of the -> operator. For example:
var r: future Int32 := -> 6*8;
Lambdas with begin/end
It's also possible to put multiple statements in a single lambda by using begin/end. For example:
var printOut : Action<String> := s -> begin Console.WriteLine('Output: '); Console.WriteLine(s); end;
If needed, the result type of the delegate will be inferred from the type that is compatible with all types passed to result or exit. If exit is not called and and no result is assigned but an inferred return type is required, the compile will fail on this expression.
Example: QuickSort Using A Lambda Expression
When you talk to programmers that like the programming language "Haskell", they always show you how short they can write a QuickSort in Haskell. With lambda expressions you can do it the same way in Delphi Prism:
private fSort : Func<List<Int32>, List<Int32>>; (*...*) fSort := xs -> iif(xs.Count = 0, new List<Int32>, fSort( xs.Where(y -> y < xs[0]).ToList) .Concat([xs[0]]) .Concat( fSort( xs.Where(y -> y > xs[0]) .ToList)) .ToList);
The lambda returns an empty list if it is applied to an empty list. Otherwise it will take the first element of the input list as the middle element for the result list. In front of that it will insert all smaller elements, after it all bigger elements, in both cases sorted by a recursive call to the lambda expression. Although that's not a very clever implementation regarding performance and readability, it shows how powerful lambda expressions can be.
External Links
See Also
Area: Oxygene Language
Compiler version: Oxygene 5
Language Glossary — Keywords — Types — FAQ — How To