Лямбда-выражения

Лямбда-выражение — это безымянная функция, которую можно сохранить в переменной или передать другой функции как аргумент.

Виды лямбда-выражений

В PascalABC.NET удобно выделять три основных вида лямбда-выражений:

  • лямбда-преобразование — преобразует исходное значение в новое: x -> x * x;
  • лямбда-условие — определяет, выполняется ли условие для значения: x -> x mod 2 = 0;
  • лямбда-проекция — преобразует составной объект в одну из его частей: x -> x.Age.

Переменная функционального типа

Переменная функционального типа может хранить лямбда-выражение; тип такой переменной должен указываться явно.

begin
  var f: real -> real := x -> x*x;
  var pred: (real,real) -> boolean := (x,y) -> x < y;

  f(5).Print;
  pred(3,2).Print;
end.

Результат:

25 False

Лямбда-преобразование

Лямбда-преобразование вычисляет новое значение по исходному элементу, сохраняя или изменяя его тип.

begin
  var a := Arr(1..5);

  var squares := a.Select(x -> x * x);

  squares.Println;
end.

Результат:

1 4 9 16 25

Лямбда-преобразование может возвращать значение другого типа.

begin
  var a: array of integer := Arr(1..5);

  var strings: array of string := a.Select(x -> x.ToString).ToArray;

  strings.Println;
end.

Результат:

1 2 3 4 5

Лямбда-условие

Лямбда-условие возвращает логическое значение для заданного значения и используется для отбора элементов по заданному критерию.

begin
  var a := Arr(1..10);

  var even := a.Where(x -> x mod 2 = 0);

  even.Println;
end.

Результат:

2 4 6 8 10

Лямбда-проекция

Лямбда-проекция преобразует составной объект в одну из его частей.

begin
  var items := [
    ('apple',1.5),
    ('banana',1.2),
    ('cherry',0.9)
  ];

  var names := items.Select(x -> x.Item1);

  names.Println;
end.

Результат:

apple banana cherry

Лямбда как параметр функции

Лямбда передаётся в функцию как параметр и применяется к каждому элементу массива.

Обобщённая функция Transform может преобразовывать массив элементов одного типа в массив элементов другого типа.

function Transform<T,T1>(a: array of T; f: T -> T1): array of T1;
begin
  Result := new T1[a.Length];

  for var i := 0 to a.Length - 1 do
    Result[i] := f(a[i]);
end;

begin
  var a := [1,2,3,4,5];

  Transform(a, x -> x*x).Println;
  Transform(a, x -> $'#{x}').Println;
  Transform(a, x -> x.IsEven).Println;
end.

Результат:

1 4 9 16 25
#1 #2 #3 #4 #5
False True False True False

Условие и преобразование в одной цепочке

Лямбда-условия и лямбда-преобразования можно последовательно применять к одной последовательности.

begin
  var a := Arr(1..10);

  a.Where(x -> x mod 2 = 0)
   .Select(x -> x * x)
   .Println;
end.

Результат:

4 16 36 64 100

Сначала Where отбирает элементы по условию, затем Select преобразует отобранные значения.

Генерация массива по индексу

ArrGen создаёт массив, вычисляя каждый элемент по его индексу с помощью лямбда-преобразования.

begin
  var a := ArrGen(10,i -> i*i,1);

  a.Println;
end.

Результат:

1 4 9 16 25 36 49 64 81 100

Генерация массива по предыдущему значению

ArrGen позволяет создавать последовательность, в которой каждый следующий элемент вычисляется из предыдущего.

begin
  var a := ArrGen(10,1,x -> x*2);

  a.Println;
end.

Результат:

1 2 4 8 16 32 64 128 256 512