Лямбда-выражения
Лямбда-выражение состоит из параметров, лямбда-операции -> и тела лямбда-выражения. Например:
Операнд -> Операнд + 1
(ПервыйПараметр, ВторойПараметр) -> ПервыйПараметр * ВторойПараметр
Так в программном коде может выглядеть значение функционального типа при записи в переменную:
// Переменная c — переменная функционального типа (Число)->Число со значением x->x*x пер c: (Число)->Число = x -> x * x
а так — при объявлении и вызове метода:
// 3-й аргумент — значение функционального типа (Число, Число)->Булево Сравнить(2, 3, (x, y) -> x == y) // Параметр z — параметр функционального типа метод Сравнить(x: Число, y: Число, z: (Число, Число)->Булево) ;
Лямбда-выражение — это анонимная функция, то есть для нее не требуется указывать имя, и в системе она не привязана к идентификатору. Анонимность и компактность лямбда-выражений позволяют записывать весь метод целиком (и параметры, и результат) непосредственно в список параметров другого метода, или в тело другого метода как возвращаемое значение.
Синтаксис лямбда-выражений выглядит следующим образом:
Лямбда выражения (тело лямбды является выражением):
-
параметр -> выражение
-
(параметр-1, ..., параметр-N) -> выражение
-
(параметр-1: тип-1, ..., параметр-N: тип-N) -> выражение
Лямбда инструкции (тело лямбды является последовательностью инструкций). Используется ключевое слово метод, тело лямбда-выражения может быть многострочным и заканчивается символом ;:
-
метод(параметр) -> тело-лямбда-выражения;
-
метод(параметр-1, ..., параметр-N) -> тело-лямбда-выражения
-
метод(параметр-1: тип-1, ..., параметр-N: тип-N) -> тело-лямбда-выражения
Примеры:
Лямбда выражения:
x -> x + 1 // один параметр (x: Число) -> x + 1 // один параметр с типом (x, y) -> x + y // два параметра (x: Число, y: Число) -> x + y // два параметра с типом
Лямбда инструкции:
- один параметр:
метод(x) -> возврат x + 1 ;
- один параметр с типом:
метод(x: Число) -> возврат x + 1 ;
- два параметра:
метод(x, y) -> возврат x + y ;
- два параметра с типом:
метод(x: Число, y: Число) -> возврат x + y ;
Захват контекста
В момент создания лямбда-выражения (когда исполнение кода доходит до места, где описано лямбда-выражение) захватываются значения используемых в лямбда-выражении локальных переменных внешнего метода.
Привязка лямбда-выражения к переменным внешнего метода называется замыканием, а сами эти переменные называются свободными или нелокальными. Таким образом, лямбда-выражение позволяет вложить один метод в другой, а замыкание позволяет связать метод с внешней переменной. Захват контекста предполагает определенные ограничения:
- Запрещается использовать в параметрах лямбда-выражения переменные, объявленные вне
тела лямбда-выражения (переменная Сообщение определена
раньше):
метод Скрипт(Имя: Строка): Строка пер Сообщение = "Привет, " пер Печать = (Сообщение: Строка, Имя: Строка) -> Сообщение + Имя + "!" возврат Печать() ;
- Запрещается объявлять или изменять в теле лямбда-выражения переменные, объявленные вне тела лямбда-выражения (переменная
Сообщение определена
раньше):
метод Скрипт(Имя: Строка): Строка пер Сообщение = "Привет, " пер Печать = метод() -> пер Сообщение = "Добро пожаловать, " возврат Сообщение + Имя + "!" ; возврат Печать() ;
- Запрещается изменять переменные после их использования в лямбда-выражении
(разрешается
до):
метод Скрипт(Имя: Строка): Строка пер Печать = метод() -> возврат Сообщение + Имя + "!" пер Сообщение = "Привет, " // Ошибка, т.к. переменная не определена ; возврат Печать() ;
илиметод Скрипт(Имя: Строка): Строка пер Печать = метод() -> возврат Сообщение + Имя + "!" ; пер Сообщение = "Привет, " // Ошибка, т.к. переменная не определена возврат Печать() ;
- В
циклах:
метод Скрипт() пер Сообщение = "Привет, " пер Имя = "" пер СписокИмён = ПолучитьСписокИмён() пер Печать = метод() -> пер Приветствие: Массив<Строка> для Имя из СписокИмён // Ошибка, т.к. переменная уже определена Приветствие.Добавить(Сообщение + Имя + "!") ; возврат Приветствие ; пер Результат = Печать() ;
илиметод Тест() пер п = 4 для i = 1 по 5 п += i // Ошибка, т.к. переменная может меняться после захвата лямбдой на 2 шаге цикла знч Лямбда = () -> п ; ;
Отладка и стек исключений
В отладке и стеке исключений лямбда-выражения выглядят как обычные методы.
Имена методов лямбда-выражений формируются как:
имя-метода-с-лямбдой$мета-имяномер-лямбды$имя-вложенной-лямбды$...
где мета-имя это имя параметра на текущем языке компиляции, в качестве которого передано лямбда-выражение.
Пример:
метод тест() знч л0 = метод() -> //тест$0 знч л0л0 = () -> 5 //тест$0$0 ; знч л1 = метод() -> //тест$1 знч л1л0 = () -> 5 //тест$1$0 ; ; метод тест2() знч л0 = лямбда1(x->x) //тест2$лямбда20 ; метод лямбда1(лямбда2: (Число)->Число): (Число)->Число возврат лямбда2 ;