From: ····@my-deja.com
Subject: a little question
Date: 
Message-ID: <8eav4l$iik$1@nnrp1.deja.com>
I have read some materials telling the differences between dynamic and
static scope. But I still quite understand to it. Can some give me a
example and give some explaination? Thanks a lot in advance!

-Tony


Sent via Deja.com http://www.deja.com/
Before you buy.
From: Joe Marshall
Subject: Re: a little question
Date: 
Message-ID: <uitx2qq9l.fsf@alum.mit.edu>
····@my-deja.com writes:

> I have read some materials telling the differences between dynamic and
> static scope. But I still quite understand to it. Can some give me a
> example and give some explaination? Thanks a lot in advance!

In very simple programs, with no `free variables' and no lambda
expressions, they work the same.  When you start using more
complicated programs, the differences show up.

Here is the rule:

  In a dynamically scoped language, a free variable has the value of
the most recent binding.

  In a statically scoped language, a free variable has the value of
the lexically visible binding.

That's probably as clear as mud.  Here's an example.  If you are using 
Emacs or XEmacs, you are using a dynamically scoped lisp, so you can
try these examples.

Suppose you had a list of numbers:  '(22 19 81 66) and you wanted to
subtract 10 from each number and form the list of results: 
'(12 9 71 56)

You know about the function MAPCAR that produces a list of answers by
applying a function to each element of a list, so you think `I'll just 
MAPCAR the subtract-10 function over my list':

(defun subtract-10 (x) (- x 10))

(mapcar #'subtract-10 '(22 19 81 66)) => (12 9 71 56)

Now it seems kinda dumb to have a `subtract-10' function that you are
using exactly once, and you figure you might end up with pages and
pages of SUBTRACT-N functions if you do this a lot, so it occurs to
you that you could use LAMBDA expression to make up a subtract-10
function on the fly.

(mapcar #'(lambda (x) (- x 10))  '(22 19 81 66)) => (12 9 71 56)

Now it occurs to you that rather than writing a literal `10' in your
code, you might want to have a value gotten from somewhere else.  So
you write this:

(defun get-a-value () 10)

(let ((y (get-a-value))) 
  (mapcar #'(lambda (x) (- x y)) '(22 19 81 66))) => (12 9 71 56)

Suppose mapcar were written like this (I'm using my-mapcar so I don't
trash my emacs):

(defun my-mapcar (f l)
  (if (null l)
      nil
      (cons (funcall f (car l)) (my-mapcar f (cdr l)))))

(let ((y (get-a-value))) 
  (my-mapcar #'(lambda (x) (- x y)) '(22 19 81 66))) => (12 9 71 56)

Everything is well and good... except, one day you type in

(let ((y (get-a-value))) 
  (my-mapcar #'(lambda (x) (- x y)) '(22 19 81 66)))

and instead of the answer, you emacs beeps at you and says:
Wrong type argument: number-char-or-marker-p, (22 19 81 66)

What happened?  Unbeknownst to you, some manager type decided that the 
variable `l' was too `lispy' and changed it to the more `Java-like'
variable `y':

(defun my-mapcar (f y)
  (if (null y)
      nil
      (cons (funcall f (car y)) (my-mapcar f (cdr y)))))

But why did this break *your* code?  Here's why:

When you wrote:

(let ((y (get-a-value))) 
  (my-mapcar #'(lambda (x) (- x y)) '(22 19 81 66)))

You introduced a `free variable' into the lambda expression.  A free
variable is one that is used in the body of the lambda expression but
not named in the argument list.  When MY-MAPCAR gets around to
applying your lambda expression to some argument, it binds X to the
argument, then it encounters this free variable Y.  What should it do?

If the lisp is dynamically scoped, it asks `What *is* the most recent
binding of y?' and it sees that the most recent binding was when MY-MAPCAR
was called, and Y was bound to the list passed in.

If the lisp is lexically scoped, it says `What's *was* the binding of
Y when this function was made?' and it sees that Y was bound to the
result of (get-a-value), i.e., 10.

Back when MY-MAPCAR was using L as the argument name, the most recent
binding of Y was when you bound it with the let statement, so
everything worked.

Emacs lisp is dynamically scoped, so you get the error message.
CommonLisp and Scheme are lexically scoped, so if you try it there,
you won't.

--
~jrm