Понимание выражения "пусть" в Лиспе
Я чрезвычайно новичок в 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выражение.