Понимание выражения "пусть" в Лиспе
Я чрезвычайно новичок в lisp, имел предыдущий опыт работы с функциональным программированием (Haskell, SML). Почему этот код возвращает 14
, а не 10
(т. е. 1 + 2y + 3 + 1
)?
(defvar x 1)
(defun g (z)
(+ x z))
(defun f (y)
(+ (g 1)
(let ((x (+ y 3)))
(g (+ y x)))))
(f 2)
2 ответа:
Потому что вы использовали
(DEFVAR X 1)
, который объявляетX
глобальной специальной переменной. Это затем заставляет каждую последующую привязкуX
использовать динамическую привязку: здесь в(LET ((X ...
.Стиль и условности в Lisp
Соглашение в Lisp: используйте
*X*
вместоX
для специальных переменных.(defvar *x* 1)
Тогда ваш код:
(defvar *x* 1) ; global special variable *X* (defun g (z) (+ *x* z)) ; use special variable *X* (defun f (y) (+ (g 1) (let ((x (+ y 3))) ; lexical binding of X (g (+ y x))))) ; use lexical binding of X
Запуск:
? (f 2) 10
Причина в том, что вы используете диалект Lisp с динамической привязкой (ссылка на хорошее описание этого из документации Emacs Lisp).
В деталях ваша программа ведет себя так, потому что новая привязка для
x
, созданная выражениемlet
, занимает место(defvar x 1)
, Когдаg
вызывается из выраженияlet
. Таким образом, вместо добавления 1 к своему аргументу функцияg
добавляет текущее значениеx
, которое равно 5, когда внутриlet
выражение.