Лямбда-выражения (PascalABC.NET)
Вот мы и подошли к материалу, который пока что в школьной информатике, как правило, не рассматривают. Мы тоже не будем подробно и научно рассматривать эти «лямбды», а обратимся к практике их использования.
Лямбда-выражения (или просто лямбды) – термин функционального программирования. Они с успехом применяются вместо уже привычных вам процедур и функций. Собственно, они и есть процедуры или функции, только безымянные. Фраза из определения подпрограммы «или идентифицированный иным образом фрагмент программного кода» как раз и подразумевает лямбды.
Лямбда-выражение представляет собой некоторое безымянное выражение, отражающее функциональную зависимость. Упрощенно, на его основе компилятор строит функцию, некоторым образом идентифицирует ее и подменяет этим идентификатором лямбда-выражение.
В коде программы лямбда-выражения легко найти по характерной паре символов ->. Это операция, которую называют по-разному, но мне нравится фраза «переходит в …». Вот пример:
x -> 3 * x * x - 6.3 * x + Sqrt(x)
Данное лямбда-выражение читается как «х переходит в 3x2+6.3x+√x». По сути, это запись функции с параметром х, которая возвращает значение выражения 3x2+6.3x+√x. Помните, в комедии «Бриллиантовая рука»: – Брюки превращаются … в элегантные шорты. Если бы там знали о лямбдах, могли сказать «переходят в …» вместо «превращаются».
(x, y) -> if x > y then x else y;
А это лямбда-функция с двумя параметрами и возвращает она максимальный из них.
x -> begin Write('Значение равно ', x:0:5) end;
Эта лямбда не возвращает значения. Возможно вы уже поняли, что так записываются лямбда-процедуры.
Чем интересы лямбды? Во-первых, их не надо заранее описывать вне вызывающей программы как отдельные функции и процедуры, а можно записывать прямо в коде программы по мере надобности. Во-вторых, как будет показано в следующих главах, лямбды очень сильно упрощают программирование многих задач, являясь параметрами (да-да, именно параметрами) подпрограмм. А еще, лямбду можно присвоить переменной и с этого момента обращаться к ней, как к именованной.
Если вы внимательно знакомились с материалом, должен был возникнуть вопрос: а как же типы? В лямбде x -> x * x какой тип имеет х? Целый, вещественный, логический? В PascalABC.NET для описания типов в лямбда выражениях существует свой синтаксис.
1 begin
2 var x: integer-> integer := t -> t * t;
3 Print(x(7)); // 49
4 x := t -> t * t * t;
5 Print(x(7)); // 343
6 x := t -> 3 * t - 1;
7 Print(x(7)) // 20
8 end.
Посмотрите на описание. Какой тип имеет переменная х? Может быть, вам это покажется странным, но ее тип integer -> integer ! Т.е. это лямбда-функция с параметром типа integer, возвращающая результат типа integer. В остальной части программы функция х переопределяется, поэтому один и тот же вызов x(7) порождает разные результаты.
Можно ли было в программе написать x := t -> t ** 3 ? Нет! Операция ** возвращает тип real, а в соответствии с описанием должен быть тип integer. Поэтому при компиляции будет выдана ошибка «Нельзя преобразовать тип real к integer».
Но если сделать описание
var x: integer -> real := t -> t * t;
в правой части лямбда-выражений можно указывать любые арифметические выражения, приводимые к real.
Написать процедуру, выводящую таблицу значений произвольной функции одного аргумента на отрезке [a;b] с шагом h.
1 procedure Tab(a, b, h: real; f: real-> real);
2 begin
3 var x := a;
4 while x <= b + h / 2 do
5 begin
6 Writeln(x:10:3, f(x):20:12);
7 x += h
8 end
9 end;
10
11 begin
12 Tab(-5, 3, 1, x -> x * x);
13 Writeln;
14 Tab(-0.9 * Pi, Pi, Pi / 8, x -> Sqr(Sin(x)) + Sqrt(Abs(x)))
15 end.
В процедуре Tab последним параметром определена лямбда-функция. В основной программе указаны два вызова Tab, где конкретизируются табулируемые функции. Вот такие они – лямбды!
PascalABC.NET позволяет «для красоты» вместо -> использовать символ → (получается при зажатой клавише Alt набором числа 26 на малой цифровой клавиатуре).