@kyanny's blog

My life. Opinions are my own.

レキシカルスコープとダイナミックスコープ

Emacs Lisp Intro で let のページを読んだ。

   Another way to think about `let' is that it is like a `setq' that is
temporary and local.  The values set by `let' are automatically undone
when the `let' is finished.  The setting only affects expressions that
are inside the bounds of the `let' expression.  In computer science
jargon, we would say "the binding of a symbol is visible only in
functions called in the `let' form; in Emacs Lisp, scoping is dynamic,
not lexical."

とあって、これがよく話題にあがるダイナミックスコープの説明(の断片)かーと思ったので試してみた。

Emacs Lisp

(defun foo ()
  (message "value of `foo' is %s" foo))
;=> foo

(let
    ((foo "FOO"))
  (foo))
;=> "value of `foo' is FOO"

Perl にただ翻訳すると、こうか?

#!/usr/bin/env perl
use strict;
use warnings;

sub foo {
    printf "value of `foo' is %s", $foo;
}

{
    my $foo = "FOO";
    foo();
}
# $ perl foo.pl 
# Global symbol "$foo" requires explicit package name at foo.pl line 6.
# Execution of foo.pl aborted due to compilation errors.

レキシカルスコープだと、自分自身のスコープか、自分自身を含んだ外側のスコープで未定義の変数は参照できなかったりするし、エラーにならなくても別のスコープの中で束縛された値にはアクセスできない。一方、ダイナミックスコープだと、関数が評価されるときにどのスコープから呼ばれたかを外側へ向かって逆にたどっていくので、関数定義の中でいきなり未定義の変数を参照してもエラーにならず値にアクセスできることがある。こういう理解で合ってるのかな?