Эта часть в substitute x n (Lambda y m)
неверна:
- комментарий гласит: "
z
нельзя использовать в M
или N
", но ничто не мешает этому. newZ
может быть переменной в n
, что приводит к проблемному c захвату - замена
z/y
не была выполнена
| otherwise = Lambda newZ newM
where newZ = fresh(used(Lambda y m))
newM = substitute x n m
Исправлено:
- "
z
нельзя использовать в M
или N
":
newZ = fresh(used m `merge` used n)
"
M[z/y][N/x]
":
newM = substitute x n (substitute y (Variable newZ) m)
Соедините:
| otherwise = Lambda newZ newM
where
newZ = fresh(used m `merge` used n)
newM = substitute x n (substitute y (Variable newZ) m)
Обратите внимание, что обновление всех привязок, как сделано выше, затрудняет понять результат и отладить подстановку. На самом деле y
нужно обновлять только если y
в n
. В противном случае вы можете оставить y
, добавив следующее предложение:
| y `notElem` used n = Lambda y (substitute x n m)
Другая идея заключается в изменении fresh
для выбора имени, похожего на старое, например, добавляя цифры до тех пор, пока не произойдет cla sh.
Все еще есть ошибка, которую я пропустил: newZ
также не должен быть равен x
(переменная, изначально подставляемая).
-- substitute [a -> \f. \x. x] in (\g. g), should be (\g. g)
ghci> substitute "a" (numeral 0) (Lambda "g" (Variable "g"))
\a. \g. \x. x
Два способа решения этой проблемы:
добавить x
к набору переменных для исключения newZ
из:
newZ = fresh ([x] `merge` used m `merge` used n)
если вы подумаете об этом, эта ошибка проявляется только тогда, когда x
отсутствует в m
, и в этом случае заменить нечего, поэтому можно добавить еще одну ветку, пропускающую работу:
| x `notElem` used m = Lambda y m
Составить:
substitute x n (Lambda y m)
--(\y.M)[N/x] = \y.M if y = x
| y == x = Lambda y m
| x `notElem` used m = Lambda y m
| y `notElem` used n = Lambda y (substitute x n m)
| otherwise = Lambda newZ newM
where newZ = fresh(used m `merge` used n)
newM = substitute x n (substitute y (Variable newZ) m)
Вывод
ghci> example
\a. \x. (\y. a) x b
ghci> numeral 0
\f. \x. x
ghci> substitute "b" (numeral 0) example
\a. \c. (\y. a) c (\f. \x. x)
Примечание. Я не пытался доказать этот код правильно ( упражнение для читателя: определите «правильно»), могут еще быть ошибки, которые я пропустил. Должен быть какой-то курс о лямбда-исчислении, в котором есть все детали и подводные камни, но я не потрудился посмотреть.