0

It's a problem in SICP book ch4,here is the code

(let ((a 1))
  (define (f x)
    (define b (+ a x))
    (define a 5)
    (+ a b))
  (f 10))

the error message is “a: undefined; cannot use before initialization”,if I use lambda expression

((lambda (a)
  (define (f x)
    (define a 5)
    (define b (+ a x))
    (+ a b))
  (f 10)) 1)

still dont work,but if I write this as procedure define,like this

(define (f a)
  (define (g x)
    (define b (+ a x))
    (+ a b))
  (g 10))
(f 1)

it runs without error,but these two are basically the same right? why the let and lambda expression failed? thanks.

codesavesworld
  • 587
  • 3
  • 10

1 Answers1

0

Because it refers to the inner a, not the one in the let:

(let ((a 1))
  (define (f x)
    (define b (+ a x))   ; `a` here refers to
    (define a 5)         ;    **this one**
    (+ a b))
  (f 10))

Internal defines are all placed in one shared scope. It is done so we can define mutually recursive functions.

If you switch the order of the two defines it'll work (put a definition above the b definition) because then a will be initialized before being used in the b initialization, but only if you use #lang racket.

In #lang sicp the following works:

(let ((a 1))
  (define (f x)
    (define a 5)
    (define b (lambda () (+ a x)))
    (+ a (b)))
  (f 10))
Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • Hi,I put the a definiton above b definiton as you said,but it still shows the same error (I use #lang sicp write this in DrRacket) – codesavesworld Mar 07 '20 at 06:27
  • just checked the `#lang sicp` indeed it throws an error. I guess it follows the `#lang r5rs`'s lead on this. nested defines are effectively in the shared `letrec`, and in R5RS it is forbidden to reference the value of letrec variable during initialiation. – Will Ness Mar 07 '20 at 06:33
  • ok...a silly question,why in b definition, the interpreter doesn't find a in let (a 1) ? I'm really comfused, thanks for helping me – codesavesworld Mar 07 '20 at 06:42
  • because you defined it to reference `a`, and there is an `a` in the inner scope, same scope where `b` is defined. put this code in Dr Racket, hover with your mouse of variables, it draws nice arrows to show what definition is referenced by which variable. – Will Ness Mar 07 '20 at 06:56
  • so the internal definiton are evaluated at the same time instead of sequentially right? – codesavesworld Mar 07 '20 at 07:06
  • @WillNess racket is not scheme, this is why it works. – alinsoar Mar 07 '20 at 09:21
  • @zenxy depends on the language specification. right now you have three: R5RS scheme, sicp, racket. see more e.g. [here](https://stackoverflow.com/a/15006018/849891). – Will Ness Mar 07 '20 at 11:13