2015-05-14 4 views
4

Я чрезвычайно новичок в lisp, имел предыдущий опыт работы с функциональным программированием (Haskell, SML). Почему этот код возвращает 14, а не 10 (т. Е. 1 + 2y + 3 + 1)?Понимание выражения «let» в LISP

(defvar x 1) 

(defun g (z) 
    (+ x z)) 

(defun f (y) 
    (+ (g 1) 
    (let ((x (+ y 3))) 
     (g (+ y x))))) 

(f 2) 

ответ

9

Потому что вы использовали (DEFVAR X 1), который объявляет X глобальной переменной. Это приводит к тому, что каждое последующее связывание X использует динамическое связывание: здесь в (LET ((X ....

Стиль Конвенция & в Лиспе

Конвенция

в 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 
3

Причина заключается в том, что вы используете диалект Лиспа с dynamic binding (ссылка на хорошее описание этого из документации Emacs Lisp).

подробно, программа ведет себя так, как это делает, потому что новая привязка для x созданного выражением let занимает место (defvar x 1) когда g вызывается из выражения let. Таким образом, вместо добавления 1 к его аргументу функция g добавляет текущее значение x, которое равно 5, когда внутри выражения let.

+0

Спасибо большое! :) – tomooka

+1

Откуда вы знаете, что это elisp? Это действительно общепринятое. – Sylwester

+0

@Sylwester: Я не знаю, что это elisp, но это была первая страница документации, которую я нашел, которая объясняла динамическое связывание лаконично. –