Lambda Expressions

From The Oxygene Language Wiki

Jump to:navigation, search

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):

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


Oxygene-48.png

Area: Oxygene Language
Compiler version: Oxygene 5

Language GlossaryKeywordsTypesFAQHow To

Navigation
Areas
More
Toolbox