Создание списка упорядоченных пар в лямбда-исчислении с использованием рекурсии
Мой ввод - два списка: l = [x1, x2, x3,...,xn] и k = [y1, y2, y3,...,yn]
Мне нужен вывод a y = [(x1,y1),(x2,y2),(x3,y3)...(xn,yn)].
Как я могу применить рекурсию к своему коду? Я мог бы сделать это для первого пункта с f = \l k. (cons (pair (head l) (head k)) empty)
но я не совсем понимаю, как использовать рекурсию для создания других элементов.
Функция "head" возвращает первый элемент списка, а функция "tail" возвращает список без первого элемента.
1 ответ
Естественно, это зависит именно от того, как вы реализовали кортежи, списки и т. Д. В Lambda Calculus. Но при условии стандартного функционала cons
списки, и что оба списка имеют одинаковую длину, и что вы уже определили следующих помощников, некоторые из которых вы уже процитировали:
cons -- construct a list from a node and another list
empty -- the empty list
head -- retrieve the first node value of a list
tail -- retrieve all but the first node of a list
pair -- pair values into a tuple
isEmpty -- return `true` if a list is `empty`, `false` otherwise
true -- return the first argument
false -- return the second argument
Затем мы можем рекурсивно сжать списки следующим образом:
ZIP = λlk. isEmpty l -- "if the list is empty…"
empty -- "return an empty result. Else…"
(cons -- "return a new list, containing…"
(pair (head l) (head k)) -- "the zipped heads, and…"
(ZIP (tail l) (tail k))) -- "everything else zipped."
Проблема, конечно, заключается в том, что в исходном лямбда-исчислении нет рекурсии. Вы не можете ссылаться на имя функции в ее собственном определении. Ответ заключается в использовании комбинатора с фиксированной запятой, например, известного Y
комбинатор.
ZIP = Y (λzlk. isEmpty l empty (cons (pair (head l) (head k)) (z (tail l) (tail k)))
Определение Y
является:
Y = λf.(λx.f(x x))(λx.f(x x))
Распутывание того, как именно это работает, - впечатляющая часть умственной гимнастики, которая не совсем подходит для этого вопроса, но использовать ее довольно просто. В общем, если у вас есть желаемое (но недопустимое, в необработанном LC) рекурсивное определение, подобное этому:
R = λ ??? . ??? R ???
Вместо этого вы можете написать это как абсолютно легальное, нерекурсивное определение:
R = Y (λr ??? . ??? r ???)
Другими словами, добавьте в вашу функцию новый параметр, который заменяет вашу рекурсивную функцию, и используйте Y
чтобы связать все для вас. Тот Y
может изобрести рекурсию с нуля, это необычно, и причина, по которой он так знаменит.