50 5.1. Основы
5.1. Основы
Процедурная (или функциональная) абстракция является ключевым свойством почти всех языков
программирования. Вместо того, чтобы переписывать одно и то же вычисление раз за разом, мы пишем
процедуру или функцию, которая проделывает это вычисление в общем виде, в зависимости от одного
или нескольких именованных параметров, а затем при необходимости вызываем эту процедуру, в каж-
дом случае задавая значения параметров. К примеру, для программиста естественно взять длинное
вычисление с повторяющимися частями вроде
(5*4*3* 2 * 1 ) + ( 7 * 6 * 5 *4 * 3 * 2 * 1 ) - (3*2*1 )
и переписать его как factorial(5) + factorial(7) - factorial(3), где
fac t o rial ( n ) = if n =0 then 1 else n * fac t o rial (n -1)
Для каждого неотрицательного числа n подстановка аргумента n в функцию factorial дает в ре-
зультате факториал n. Если мы будем писать «λn. ...» как сокращение для «функция, которая, для
каждого n, дает . . . », то определение factorial можно переформулировать как
fac t o rial = λn . if n =0 then 1 else n * fac t orial (n -1)
Теперь factorial(0) означает «функция λn. if n=0 then 1 else ..., примененная к аргументу 0»,
то есть, «значение, которое получается, если аргумент n в теле функции (λn. if n=0 then 1 else
...) заменить на 0», то есть, «if 0=0 then 1 else ...», то есть, 1.
Лямбда-исчисление (или λ-исчисление) воплощает такой способ определения и применения функций
в наиболее чистой форме. В лямбда-исчислении все является функциями: аргументы, которые функции
принимают — тоже функции, и результат, возвращаемый функцией — опять-таки функция.
Синтаксис лямбда-исчисления признает три вида термов.
1
Переменная x сама по себе терм; абстрак-
ция переменной x в терме t
1
, что записывается как λx.t
1
, тоже терм; и, наконец, применение терма t
1
к
терму t
2
— третий вид термов. Эти способы построения термов выражаются следующей грамматикой:
t ::= термы:
x переменная
λx. t абстракция
t t применение
В следующих подразделах исследуются некоторые детали этого определения.
5.1.1. Абстрактный и конкретный синтаксис
При обсуждении синтаксиса языков программирования полезно бывает различать два уровня
2
структуры. Конкретный (или поверхностный) синтаксис языка относится к строкам символов, кото-
рые читают и пишут программисты. Абстрактный синтаксис — это намного более простое внутреннее
представление программ в виде размеченных деревьев (они называются абстрактные синтаксические
деревья или АСД ). Представление в виде дерева делает структуру термов непосредственно очевид-
ной, и поэтому его естественно использовать для сложной обработки, которая нужна как при строгом
определении языков (и доказательстве их свойств), так и внутри компиляторов и интерпретаторов.
Преобразование из конкретного в абстрактный синтаксис происходит в два этапа. Сначала лексиче-
ский анализатор (или лексер) переводит последовательность символов, написанных программистом, в
последовательность лексем — идентификаторов, ключевых слов, комментариев, символов пунктуации,
и т. п. Лексический анализатор убирает комментарии и решает вопросы, связанные с пробельными сим-
волами, соглашениями о больших/маленьких буквах, а также форматах для числовых и символьных
1
Выражение лямбда-терм относится ко всем термам лямбда-исчисления. Лямбда-термы, которые начинаются с λ,
часто называют лямбда-абстракциями.
2
Определения полноценных языков иногда используют еще больше уровней. Например, вслед за Ландином, часто
полезно определять поведение некоторых конструкций языка в качестве производных форм, путем перевода их в комби-
нации других, более элементарных, конструкций. Ограниченный язык, состоящий только из этих базовых конструкций,
часто называют внутренним языком, а полный язык, который включает в себя все производные формы, называет-
ся внешним языком. Трансформация из внешнего языка во внутренний выполняется (по крайней мере, концептуально)
отдельным проходом компилятора, вслед за синтаксическим анализом. Производные формы обсуждаются в Разделе 11.3.
rev. 104