147pm
147pm

Reputation: 2239

common lisp's let binds, not executes?

In this code

(defun foo ()
   . . .
   (let ((bar (foo)))
      (if bar
         . . .)))

in the let line, let is only binding, right? It doesn't actually run foo. I assume foo is run (recursively) for the first time in the if statement, correct? If what I assume is correct, is there a way to have let actually execute foo and then assign the results to bar?

Upvotes: 1

Views: 99

Answers (2)

Joshua Taylor
Joshua Taylor

Reputation: 85813

There's an answer that shows an example that illustrates the behavior of let. However, an example via an implementation doesn't answer conclusively whether it's supposed to behave that way, or whether implementations are free to do different things, or whether there's a bug in the implementation. To know what's supposed to happen, you need to check the documentation. Fortunately, the Common Lisp HyperSpec is freely available online. The documentation for let says:

Special Operator LET, LET*

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.

The form

 (let ((var1 init-form-1)
       (var2 init-form-2)
       ...
       (varm init-form-m))
   declaration1
   declaration2
   ...
   declarationp
   form1
   form2
   ...
   formn)

first evaluates the expressions init-form-1, init-form-2, and so on, in that order, saving the resulting values. Then all of the variables varj are bound to the corresponding values; each binding is lexical unless there is a special declaration to the contrary. The expressions formk are then evaluated in order; the values of all but the last are discarded (that is, the body of a let is an implicit progn).

Thus, all the forms are evaluated (executed), then the results are bound the values, and then the forms in the body are evaluated.

Upvotes: 5

Guilherme
Guilherme

Reputation: 618

In the example you provided, foo is evaluated and then assigned to bar. You can test this by simply evaluating something like:

(let ((foo (+ 1 2)))
  (if (= foo 3)
      foo
      nil))
; => 3

cf. PCL: Syntax and Semantics or Lispdoc.

Edit

As @paulo-madeira brought up in the comments, this is not enough to test, since you don't know when each one was evaluated. See his comment for a way to test it using FORMAT. Anyway, the takeaway is, the LET you propose evaluates foo and assigns it to bar, which means your function foo is defined in terms of itself, which means you're up to no good.

Upvotes: 2

Related Questions