Введение

Функциональный язык программирования

Unlambda — минималистичный, "почти чистый" функциональный язык программирования, изобретённый Дэвидом Мадором. Он основан на комбинаторной логике — системе выражений, не использующей оператор лямбда или свободные переменные. В его основе лежат главным образом две встроенные функции (s и k) и оператор применения (обозначается `, обратная кавычка). Одних лишь этих функций достаточно для достижения полноты по Тьюрингу, но также предусмотрены функции ввода/вывода (I/O) для взаимодействия с пользователем, вспомогательные функции и функция ленивых вычислений. Переменные не поддерживаются. Unlambda является свободным программным обеспечением с открытым исходным кодом, распространяемым по лицензии GNU General Public License (GPL) версии 2.0 или более поздней.

Оригинальные встроенные функции

Обозначение x обозначает функцию, которая принимает один аргумент и возвращает его без изменений, печатая единственный символ x как побочный эффект при её вызове. i представляет собой версию функции идентичности, которая не имеет такого побочного эффекта; она используется здесь в качестве фиктивного аргумента. Программа `.di` применяет функцию печати d к фиктивному аргументу i, возвращая i и печатая букву d как побочный эффект. Аналогично, ``.l.di` сначала применяет l к d, печатая букву l и возвращая d; этот результат d затем применяется к i, как в предыдущем примере. Функция r является синтаксическим сахаром для функции, которая печатает символ новой строки. Другие важные возможности, предоставляемые Unlambda, включают функции k и s. k создает константные функции: результат `kx` — это функция, которая при вызове возвращает x. Таким образом, значение ``kxy` равно x для любого x и y.

s — обобщенный оператор вычисления. ``sxyz` вычисляется как ``xz``yz` для любых x, y и z. Примечательно, что s и k достаточны для выполнения любого вычисления, как описано в комбинаторной логике SKI. В качестве краткого примера, функция идентичности i может быть реализована как ``skk`, поскольку ``skkx` дает x для всех x.

Единственная конструкция управления потоком в Unlambda — это вызов с текущим продолжением, обозначаемый c. Когда вычисляется выражение вида `cx`, создается специальный объект продолжения, представляющий состояние интерпретатора в этот момент. Затем вычисляется x, и результат передается объекту продолжения в качестве аргумента. Если продолжение никогда не применяется к аргументу, значение выражения `cx` равно значению x. Но если объект продолжения применяется к значению y, выполнение x немедленно прерывается, и значение всего выражения `cx` становится равным y.

Семантика выполнения Unlambda обычно является строгой (eager evaluation), но существует опция ленивого вычисления (lazy evaluation), обозначаемая использованием оператора d. Обычно, для вычисления выражения вида `xy`, Unlambda сначала вычисляет x, затем y, а затем применяет x к y. Однако, если x вычисляется в специальное значение d, то y не вычисляется; вместо этого, значение выражения `dy` является специальным объектом "отложенного вычисления", который, при применении к аргументу z, вычисляет y, а затем применяет его значение к z. При отсутствии побочных эффектов это точно то же самое, что и `iy`. Разница заключается в том, что `iy` выполняет любые побочные эффекты в y немедленно, тогда как `dy` откладывает побочные эффекты до тех пор, пока результат не будет применен к другому аргументу. Следующий встроенный оператор Unlambda — v, который игнорирует свой аргумент и возвращает v. Эта возможность не является строго необходимой, поскольку v можно реализовать как ``s``k``s``s``kskk``k``s``s``kskk`, но она предоставляется для удобства. (Это выражение выше просто `Yk`, где Y обозначает комбинатор фиксированной точки.)

Встроенные функции версии 2

В Unlambda версии 2 было добавлено больше встроенных функций. Ввод облегчается операторами @ и ?u. Когда @ применяется к функции x, из ввода считывается символ и сохраняется как "текущий символ"; затем к x применяется i. Однако, если на входе больше нет символов, текущий символ остаётся неопределённым, и к x применяется v вместо этого. Когда к функции x применяется функция ?u, результатом является вычисление `xi, если текущий символ равен u, иначе вычисляется `xv. Также существует оператор "повторного вывода" |. При вычислении `|x функция x применяется к u, если u является текущим символом, или к v, если текущий символ отсутствует. Наконец, есть оператор выхода e. Когда e применяется к x, выполнение программы завершается, а x считается результатом программы (большинство существующих интерпретаторов игнорируют результат в любом случае).