Understanding "let" expression in LISP
Asked Answered
P

2

5

I am extremely new to lisp, had previous experience with functional programming (Haskell, SML). Why is this code returning 14, and not 10 (i.e. 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)
Pitsaw answered 14/5, 2015 at 20:24 Comment(0)
I
11

Because you used (DEFVAR X 1), which declares X to be a global special variable. This then causes every other later binding of X to use dynamic binding: here in (LET ((X ....

Style & Convention in Lisp

Convention in Lisp: use *X* instead of X for special variables.

(defvar *x* 1)

Your code then is:

(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

run:

? (f 2)
10
Invalidism answered 14/5, 2015 at 21:40 Comment(0)
W
4

The reason is that you are using a Lisp dialect with dynamic binding (link to a good description of this from the Emacs Lisp documentation).

In detail, your program behaves the way it does is because the new binding for x created by the let expression takes the place of the (defvar x 1) when g is called from within the let expression. So, instead of adding 1 to its argument, the g function adds the current value of x, which is 5 when inside the let expression.

Wein answered 14/5, 2015 at 20:34 Comment(2)
How do you know this is elisp? This is valid common-lisp as well.Tasteless
@Sylwester: I don't know it is elisp, but that was the first documentation page I found that explained dynamic binding succinctly.Wein

© 2022 - 2024 — McMap. All rights reserved.