Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding "let" expression in LISP

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)
like image 289
tomooka Avatar asked May 14 '15 20:05

tomooka


People also ask

What are let and let * forms in Lisp?

let and let* create new variable bindings and execute a series of forms that use these bindings. let performs the bindings in parallel and let* does them sequentially. first evaluates the expressions init-form-1, init-form-2, and so on, in that order, saving the resulting values.

How does let work in Scheme?

In Scheme, you can use local variables pretty much the way you do in most languages. When you enter a let expression, the let variables will be bound and initialized with values. When you exit the let expression, those bindings will disappear.

What is Lisp expression?

LISP expressions are called symbolic expressions or s-expressions. The s-expressions are composed of three valid objects, atoms, lists and strings. Any s-expression is a valid program. LISP programs run either on an interpreter or as compiled code.

What is SETQ in Lisp?

1.9. 2 Using setq This special form is just like set except that the first argument is quoted automatically, so you don't need to type the quote mark yourself. Also, as an added convenience, setq permits you to set several different variables to different values, all in one expression.


2 Answers

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
like image 96
Rainer Joswig Avatar answered Sep 27 '22 17:09

Rainer Joswig


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.

like image 37
Greg Hewgill Avatar answered Sep 27 '22 18:09

Greg Hewgill