[plt-scheme] binding construct scoping issue

From: Carl Eastlund (carl.eastlund at gmail.com)
Date: Tue Dec 23 14:09:43 EST 2008

The even? and odd? functions are defined in PLT Scheme -- some of your
code is calling the builtins, rather than your own definitions.

--Carl

On Tue, Dec 23, 2008 at 1:58 PM, apatinoii at gmail.com
<apatinoii at gmail.com> wrote:
> I've become a bit befuddled over binding constructs.
> In particular, I was under the impression that a normal let expression
> was not able to define mutually recursive procedures. The r6rs and the
> plt-reference imply this through their explanation of letrec. Yet,
>
> (let ((even? (lambda (n)
>               (if (= n 0)
>                   #t
>                   (odd? (- n 1)))))
>      (odd? (lambda (n)
>              (if (= n 0)
>                  #f
>                  (even? (- n 1))))))
>  (even 20))
> => #t
>
> works just fine using both mzscheme and ypsilon.
> TSPL3 describes let as a syntactic extension, expanding into an
> application of a lambda expression. Therefore, I assumed that the
> previous expression would be expanded into the form:
>
> ((lambda (even? odd?)
>   (even? 20)) (lambda (n)
>                 (if (= n 0)
>                     #t
>                     (odd? (- n 1))))
>               (lambda (n)
>                 (if (= n 0)
>                     #f
>                     (even? (- n 1)))))
> => #t
>
> which works as well. Why does this work? Both lambda arguments are
> defined outside of the body of the calling lambda. Therefore, the
> variables within them should be resolved outside. Isn't this dynamic
> scoping? For example, the following expressions work as expected:
>
> ((lambda (x f) (f)) 1 (lambda () x))
> ((lambda (g) (define x 1) (g)) (lambda () x))
>
> which both result in errors; x is unidentified.
> So, exactly what does let expand to?
>
> Another difficulty I'm having, concerning the same topic, but focused
> more on the algorithm, involves defining the same mutually recursive
> functions, only using named-let instead:
>
> (let even? ([n 20] [odd? (lambda (n)
>                           (and (not (= n 0))
>                                (even? (- n 1))))])
>  (or (= n 0)
>      (odd? (- n 1))))
>
> which works as well, although by looking at its presumed expansion:
>
> ((lambda (n odd?)
>   (define even?
>     (lambda (x f)
>       (or (= x 0)
>           (f (- x 1)))))
>   (even? n odd?)) 20 (lambda (n)
>                        (and (not (= n 0))
>                             (even? (- n 1)))))
>
> appears it shouldn't, since again, the lambda is passed from outside.
> In this case, can anyone tell me why this works given that the even?
> procedure called inside of the lambda argument only takes one
> argument (even? (- n 1)), while inside it is defined to take two
> arguments?


Posted on the users mailing list.