Rの環境とスコープ
Itoshi NIKAIDO <dritoshi@gmail.com>
Rはすべてがオブジェクト
vector, matrix, 関数...
ひとつのクラスに属する
オブジェクトを上書きされたくない
関数を呼び出す
パッケージを読み込む
どのような
オブジェクトが利用可能か?
Lexical scoping
複数の環境からオブジェクトを探す・環境を作成
する規則
environment
環境
environment
= frame + enclosure
environment
= frame + enclosure

 symbol    value
  x  1
environment
= frame + enclosure

 環境へのpointer
 どの環境と結びついているのか?
環境の構造
線形のツリー



   emptyenv()


          baseenv()

                 ...


                       ...


                             globalenv() .GlobalEnv

                             いわゆるワークスペース
                             コンソールやスクリプトからの入力さ
                             れたオブジェクトが格納される
                             ※ 関数やパッケージは別
Search Path
オブジェクトを検索する順序



   emptyenv() R_EmptyEnv

                                     search path: オブジェクト
          baseenv() base
                                     を検索する環境の順序
                 ...                 search()


                       ...


                             globalenv() R_GlobalEnv
Package やデータがロードされると...
library() と attach()



      emptyenv() R_EmpltyEnv


               baseenv() base
                                      ロードされたオブジェクトはbase
                       ...            と.GlobalEnvの間に置かれる
                                      library()
                             ...      attach()


                                   globalenv() R_GlobalEnv
関数を定義すると...
クロージャ環境が作られ、呼び出されるたびに評価環境が生成される



   emptyenv() R_EmpltyEnv         関数を定義する
                                  その環境を含む環境が作られる
          baseenv() base          = closure 環境

                 ...              関数を呼び出す
                                  クロージャー環境を元に環境
                       ...        (評価環境)が作られて、
                                  1番目に置かれる
                             globalenv() R_GlobalEnv

 関数が環境とセットになっているので、関数は自分の場所を知っている。
 R はこれを利用してオブジェクトを探す。
 このようなスコープ規則のことを Lexical scope と呼ぶ
 このような関数のことをクロージャ関数と呼ぶ
関数の引数はいつ評価されるのか
call-by-value と lazy evaluation



      emptyenv() R_EmpltyEnv                 関数を定義する
                                             その環境を含む環境が作られる
               baseenv() base                = closure 環境

                        ...                  関数を呼び出す
                                             クロージャー環境を元に環境
                                  ...        (評価環境)が作られて、
                                             1番目に置かれる
                                        globalenv() R_GlobalEnv
            1. 関数が呼び出されると、評価環境の引数マッチング規則で
            仮引数と実引数が照合される
            2. 関数が評価される
            3. 引数が必要になったら、引数で与えられた値に初期化される (遅延評価)
            このとき値のポインタではなく、値そのものに置き変わる (値渡し)
            (遅延評価は予約オブジェクトで達成しているが説明を割愛)
サーチパスを制御したい
サーチパスの例外的な処理である名前空間を利用する


     emptyenv() R_EmpltyEnv    - 同名のオブジェクトを区別する
                               - オブジェクトのカプセル化
                               をするための例外 = namespace
            baseenv() base

                               0. オブジェクトを提供するパッケージ
                   ...
                               の名前空間
                               1. インポートされオブジェクト
3. search path                 2. base パッケージの名前空間

                              globalenv() R_GlobalEnv
Rで環境を操作する
環境の情報を得る


   emptyenv() R_EmpltyEnv               検索する

                   parent.env()         environment(ls)
          baseenv() base           存在の確認
                                   exists(“+”, env = baseenv())
                 ...

search()                          環境を作る
                       e1
searchpaths()                     e1 <- new.env()
topenv()
                            globalenv() R_GlobalEnv
Rで環境を操作する
環境に対する変数の操作


   emptyenv() R_EmpltyEnv


            baseenv() base
   # 変数を割り当てる
   > assign("a", 1:10, envir = baseenv())

   # 検索する
   > exists("a", envir = globalenv(), inherits = FALSE)
   [1] FALSE
   > exists("a", envir = baseenv(), inherits = FALSE)
   [1] TRUE

   # 変数を検索して、値を取り出す
   > mget("a", envir = baseenv())
   $a
    [1] 1 2 3 4 5 6 7 8 9 10

   > get("a", envir = baseenv())
    [1] 1 2 3 4 5 6 7 8 9 10
Rで名前空間を操作する
名前空間の情報を得る・パッケージ内の変数にアクセスする




# 名前空間の情報             # 変数にアクセスする
loadedNamespaces()    # Package::name
                      # export() されている関数
# 名前空間の操作             base::log
loadNamespace(ns)
unloadNamespace(ns)   # Package:::name
attachNamespace(ns)   # export() されていない関数
                      library(“Package”)
# 名前空間の作成             Package:::name
asNamespace(“name”)
# エクスポート              # 関数を適用
namespaceExport(ns)   eapply(env, FUN)
Rでは環境はどのように表現されているか
実は単なる list



R> e <- new.env()
R> e
<environment: 0x103186150>
R> e$a <- 1
R> e$b <- "hoge"
R> e$b

# 環境を list にする
R> as.list(e)
$a
[1] 1

$b
[1] "hoge"
環境は参照渡し
Rは基本的に値渡しであるが環境は例外

R> e <- new.env()
R> e2 <- e
R> e
<environment: 0x103186150>
R> e2
<environment: 0x103186150>
# 同じポインタをさしている


R> e$a
NULL
# e2 に a をつくる
R> e2$a <- 1
R> e2$a
1
# 参照渡しなのでe にも a ができている
R> e$a
[1] 1
まとめ
オブジェクトを上書きしたくなかった




• Rは Lexical scope rule で使えるオブジェクトを知ることができる
• Rは環境によって Lexical scope を達成していた
• ユーザが環境を作ることでスコープルールに基いたオブジェクトを生
  成・管理できる

• Namespaceでスコープルールの例外を作り、ユーザがそのスコープ範囲
  を決めることができる。Rでは後付けの実装なので今でも仕様が若干変

  化中
参考資料
論文、オンラインドキュメント、書籍




  • Lexical Scope and Statistical Computing
  • The R Language Definition

  • Rプログラミングマニュアル
  • Rの基礎とプログラミング技法

Rの環境とスコープ