Задача состоит в том, чтобы написать интерпретатор для нетипизированного лямбда-исчисления, используя как можно меньше символов. Мы определяем нетипизированное лямбда-исчисление следующим образом:
Синтаксис
Существуют следующие три вида выражений:
Лямбда-выражение имеет форму,
(λ x. e)
гдеx
может быть любое допустимое имя переменной иe
любое допустимое выражение. Здесьx
называется параметром иe
называется телом функции.Для простоты мы добавим еще одно ограничение: не должно быть переменной с тем же именем, что и в
x
настоящее время в области видимости. Переменная начинает находиться в области видимости, когда ее имя появляется между(λ
и.
и перестает быть в области видимости соответствующей области)
.- Функция приложения имеет вид
(f a)
гдеf
иa
являются юридическими выражениями. Здесьf
называется функция иa
называется аргументом. - Переменная имеет вид
x
гдеx
допустимое имя переменной.
Семантика
Функция применяется путем замены каждого вхождения параметра в теле функции своим аргументом. Более формально выражение формы ((λ x. e) a)
, где x
это имя переменной и e
и a
являются выражениями, оценивает (или уменьшает) к выражению e'
где e'
является результатом замены каждого вхождения x
в e
с a
.
Нормальная форма - это выражение, которое не может быть оценено в дальнейшем.
Соревнование
Ваша миссия, если вы решите принять ее, - написать интерпретатор, который принимает в качестве входных данных выражение нетипизированного лямбда-исчисления, не содержащее свободных переменных, и выдает в качестве выходных данных нормальную форму выражения (или выражение, альфа-конгруэнтное ему) , Если выражение не имеет нормальной формы или не является допустимым выражением, поведение не определено.
Решение с наименьшим количеством символов выигрывает.
Пара заметок:
- Входные данные могут быть либо прочитаны из стандартного ввода, либо из имени файла, заданного в качестве аргумента командной строки (вам нужно только реализовать одно или другое, а не оба). Вывод идет в стандартный вывод.
- В качестве альтернативы вы можете определить функцию, которая принимает входные данные в виде строки и возвращает выходные данные в виде строки.
- Если символы не ASCII для вас проблематичны, вы можете использовать
\
символ обратной косой черты ( ) вместо λ. - Мы считаем количество символов, а не байтов, поэтому даже если ваш исходный файл в кодировке Unicode λ считается одним символом.
- Допустимые имена переменных состоят из одной или нескольких строчных букв, то есть символов между a и z (нет необходимости поддерживать буквенно-цифровые имена, прописные буквы или нелатинские буквы - хотя это, конечно, не сделает ваше решение недействительным).
- Что касается этой проблемы, то круглые скобки не являются обязательными. Каждое лямбда-выражение и каждое приложение функции будут заключены ровно в одну пару скобок. Имя переменной не будет заключено в круглые скобки.
- Синтаксический сахар, такой как запись
(λ x y. e)
для(λ x. (λ y. e))
, не нуждается в поддержке. - Если для оценки функции требуется глубина рекурсии более 100, поведение не определено. Это должно быть более чем достаточно, чтобы быть реализованным без оптимизации на всех языках, и все же достаточно большим, чтобы можно было выполнять большинство выражений.
- Вы также можете предположить, что интервал будет таким же, как в примерах, то есть без пробелов в начале и конце ввода или перед
λ
или или.
и ровно через один пробел после a.
и между функцией и ее аргументом и после aλ
.
Пример ввода и вывода
Входные данные:
((λ x. x) (λ y. (λ z. z)))
Выход:
(λ y. (λ z. z))
Входные данные:
(λ x. ((λ y. y) x))
Выход:
(λ x. x)
Входные данные:
((λ x. (λ y. x)) (λ a. a))
Выход:
(λ y. (λ a. a))
Входные данные:
(((λ x. (λ y. x)) (λ a. a)) (λ b. b))
Выход:
(λ a. a)
Входные данные:
((λ x. (λ y. y)) (λ a. a))
Выход:
(λ y. y)
Входные данные:
(((λ x. (λ y. y)) (λ a. a)) (λ b. b))
Выход:
(λ b. b)
Входные данные:
((λx. (x x)) (λx. (x x)))
Вывод: что угодно (это пример выражения, которое не имеет нормальной формы)
Входные данные:
(((λ x. (λ y. x)) (λ a. a)) ((λx. (x x)) (λx. (x x))))
Вывод:
(λ a. a)
(Это пример выражения, которое не нормализуется, если вы оцениваете аргументы перед вызовом функции, и, к сожалению, пример, для которого моя попытка решения не удалась)Входные данные:
((λ a. (λ b. (a (a (a b))))) (λ c. (λ d. (c (c d)))))
Вывод:
`(λ a. (λ b. (a (a (a (a (a (a (a (a b))))))))))
это вычисляет 2 ^ 3 в церковных цифрах.
(\y. a)
.