[plt-scheme] binding construct scoping issue

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Tue Dec 23 14:14:20 EST 2008

Use Chech Syntax and look at the arrows originating from the odd? and
even? identifiers.

Use this in the Module language:

#lang scheme

(let ((even? (lambda (n)
               (if (= n 0)
                   #t
                   (odd? (- n 1)))))
      (odd? (lambda (n)
              (if (= n 0)
                  #f
                  (even? (- n 1))))))
  (even? 20))

((lambda (even? odd?)
   (even? 20)) (lambda (n)
                 (if (= n 0)
                     #t
                     (odd? (- n 1))))
               (lambda (n)
                 (if (= n 0)
                     #f
                     (even? (- n 1)))))

On Dec 23, 2008, at 2:09 PM, Carl Eastlund wrote:

> 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?
> _________________________________________________
>   For list-related administrative tasks:
>   http://list.cs.brown.edu/mailman/listinfo/plt-scheme



Posted on the users mailing list.