Пример. Обобщенная функция поиска минимального элемента в массиве. Элементы должны реализовывать интерфейс IComparable
function MinElem
where T: IComparable
begin
var min: T := a[0];
forvar i := 1 to a.Length-1 do
if min.CompareTo(a[i])<0 then
min := a[i];
Result := max;
end;
К сожалению, нет возможности использовать операцию <, поскольку операции не входят в интерфейсы.
Элементы функционального программирования
Лямбда-выражения
Лямбда-выражение - это выражение специального вида, которое на этапе компиляции заменяется на имя подпрограммы, соответствующей лямбда-выражению и генерируемой компилятором на лету.
Здесь излагается полный синтаксис лямбда-выражений.
Здесь рассказывается о захвате лямбда-выражением переменных из внешнего контекста.
Лямбда-выражения запрещается использовать при инициализации полей класса или записи, внутри вложенных подпрограмм, в подпрограмме при наличии вложенной подпрограммы, в разделе инициализации модуля.
Синтаксис лямбда-выражений достаточно сложен и в данном пункте иллюстрируется на примерах.
Пример 1.
var f: integer -> integer := x -> x*x;
f(2);
Запись x -> x является лямбда-выражением, представляющем собой функцию с одним параметром x типа integer, возвращающую x*x типа integer. По данной записи компилятор генерирует следующий код:
function #fun1(x: integer): integer;
begin
Result := x*x;
end;
...
var f: integer -> integer := #fun1;
f(2);
Здесь #fun1 - это имя, генерируемое компилятором. Кроме того, код функции #fun1 также генерируется компилятором.
Пример 2. Фильтрация четных
Обычно лямбда-выражение передаётся как параметр подпрограммы. Например, в следующем коде
var a := Seq(3,2,4,8,5,5);
a.Where(x -> x mod 2 = 0).Print;
лямбда-выражение x -> x mod 2 = 0 задаёт условие отбора чётных чисел из массива a.
Пример 3. Сумма квадратов
var a := Seq(1,3,5);
writeln(a.Aggregate(0,(s,x)->s+x*x));
Иногда необходимо явно задавать тип параметров в лямбда-выражении.
Пример 4. Выбор перегруженной версии процедуры с параметром-лямбдой.
procedure p(f: integer -> integer);
begin
write(f(1));
end;
procedure p(f: real -> real);
begin
write(f(2.5));
end;
begin
p((x: real)->x*x);
end.
В данном примере вызов p(x -> x) вызовет ошибку компиляции, потому что компилятор не может выбрать, какую версию процедуры p выбирать. Задание типа параметра лямбды помогает устранить эту неоднозначность.
Пример 5. Лямбда-процедура.
procedure p(a: integer -> ());
begin
a(1)
end;
begin
p(procedure(x) -> write(x));
end.
Захват переменных в лямбда-выражении
Лямбда-выражение может использовать переменные из внешнего контекста. Такие переменные называются захваченными лямбда-выражением.
Пример 1. Захват переменной в запросе Select.
begin
var a := Seq(2,3,4);
var z := 1;
var q := a.Select(x->x+z);
q.Println;
z := 2;
q.Println;
end.
Здесь лямбда-выражение x->x+z захватывает внешнюю переменную z. Важно заметить, что при изменении значения переменной z запрос a.Select(x->x+z), хранящийся в переменной q, выполняется с новым значением z.
Пример 2. Накопление суммы во внешней переменной.
begin
var sum := 0;
var AddToSum: integer -> () := procedure (x) -> begin sum += x; end;
AddToSum(1);
AddToSum(3);
AddToSum(5);
writeln(sum);
end.
Методы последовательностей
Все последовательности имеют множество методов обработки последовательностей, реализованных как методы расширения.
* Методы Print
* Метод фильтрации Where
* Метод проецирования Select
* Метод проецирования SelectMany
* Методы Take, TakeWhile, Skip, SkipWhile
* Метод Sorted
* Методы OrderBy, OrderByDescending
* Методы ThenBy,ThenByDescending
* Метод ForEach
* Метод Concat
* Метод JoinIntoString
* Метод Zip
* Метод Distinct
* Методы Union,Intersect,Except
* Метод Reverse
* Метод SequenceEqual
* Методы First, FirstOrDefault
* Методы Last, LastOrDefault
* Методы Single, SingleOrDefault
* Метод DefaultIfEmpty
* Методы ElementAt, ElementAtOrDefault
* Методы Any, All
* Методы Count
* Метод Contains
* Метод Aggregate
* Методы Sum, Average
* Методы Min, Max
* Метод Join
* Метод GroupJoin
* Метод GroupBy
* Метод AsEnumerable
* Методы ToArray, ToList
* Метод ToDictionary
* Метод ToLookup