RU beehive logo ITEC dept promo banner
ITEC 380
2009spring
ibarland

homeinfolecturesexamshwsarchive

lect10
scope


Scope

We have already seen that Scheme has a let statement; it can actually be implemented in terms of a function-call:

(let {[a 2]
      [b 4]}
   (+ 3 a b))

=
((lambda (a b) (+ 3 a b))
 2 4)
=
(+ 3 2 4)
=
9
Quiz: If we give a definition for a outside the let, what does it return? Moreover, what do you expect it to return?:
(define a 1)

(let {[a 2]
      [b (sqr a)]}
   (+ 3 a b))
What if we wanted the other version?

Scheme does happen to provide let*. let* can be implemented by expanding it into nested lets.1 Here's an example:

(define a 1)

(let* {[a 2]
       [b (+ sqr a)]}
   (+ 3 a b))

=     ; Rewrite as nested lets:
(let {[a 2]}
  (let {[b (sqr a)]}
   (+ 3 a b)))

=     ; Which, following the already-known rules, becomes:
((lambda (a)
   (let {[b (sqr a)]}
      (+ 3 a b)))
 2)

=   ; Note how there's no confusion about using the global a=1.

(let {[b (sqr 2)]}
  (+ 3 2 b))

= 

(let {[b 4]}
  (+ 3 2 b))


=    ; Now, follow regular ol' rules for evaluation a function-application:

   ((lambda (b)
       (+ 3 2 b))
    4)

=  (+ 3 2 4)

=  9

Finally, what about a version where the scope includes the current let-branch? For variables, this is never desirable ('variable used before initialized'), but it is necessary for recursive functions:

(define (insert-sort lon)
  (letrec {[insert (lambda (n nums)
                     (cond [(empty? nums) (list n)]
                           [(cons? nums)  (if (< n (first nums))
                                              (cons n nums)
                                              (cons (first nums) (insert n (rest nums))))]))]}
    (foldl insert empty lon)))




; Another example, using mutual recursion:
(letrec {[a 2]
         [even? (lambda (n) (or (zero? n) (odd? (sub1 n))))]
         [odd?  (lambda (n) (not (even? n)))]}
  (even? a))
In particular, look closely at insert-sort: Because insert is just a local variable, it has effectively made its helper-function private.

There are also wacky ways to explore exactly how Java's scoping works (it's different for fields vs. locals). See also: a silly main.


Implementing fields. Note that each (pair of) functions has its own closure.


dynamic scope

Dynamic scope: (Lisp; Perl.)

class Foo() {
  int x = 3;

  void foo() {
    ++x;        // If dynamically scoped: refers to 'most recently declared' x
    print(x);   // in a *dynamic* sense!
    }

  void haha() {
    foo();
    }

  void lala() {
    int x = 9;
    foo();
    }

  void gaga() {
    int x = 5;
    foo();
    }

  }


class Hoo() {
  int x;
  Foo.foo();
  }
Easy to implement, though (in an interpreter):

Other ways of controlling access:


1 (Therefore, let* isn't really a primitive scoping mechanism; it's just convenient syntactic sugar. In the same way that let itself can be thought of as syntactic sugar for passing to a parameter.)      

homeinfolecturesexamshwsarchive


©2009, Ian Barland, Radford University
Last modified 2009.Apr.20 (Mon)
Please mail any suggestions
(incl. typos, broken links)
to iba�rlandrad�ford.edu
Powered by PLT Scheme