少しだけ参照透明なR言語の変数スコープ

2時間以上ハマったのでシェア。

> a<-2; { a<-3; }; a
3
> x <- data.frame(a=1,b=2,c=3)
> set_c_func <- function(df) { df$c <- 123; return(df) }
> set_c_func(x)
  a b   c
1 1 2 123
> print(x)
  a b c
1 1 2 3
> set_c_func <- function(df) { df$c <<- 123; return(df) }
> set_c_func(x)
Error in df$c <<- 123 : object of type 'closure' is not subsettable
> set_c_func <- function(df) { df <<- data.frame(c=123); return(df) }
> set_c_func(x)
Error in set_c_func(x) : cannot change value of locked binding for 'df'
> set_c_func <- function() { x$c <<- 123; }
> set_c_func()
> x
  a b   c
1 1 2 123

まとめると、

  • R言語の変数はブロックスコープを持たず、関数スコープを持つ。呼び出しは「値渡し」
    • 値渡しはプログラミングモデル上の話で、処理系は参照を渡してcallee側で環境の差分だけを持つように効率よく実装されてるはず
  • ブロック内で左辺値として使う変数はすべて関数内ローカルな変数として扱われる
    • その関数内に限って通常の代入'<-'演算子で破壊代入可能
  • '<<-'を使うと、親スコープの変数を破壊代入可能
    • ただし親スコープ変数を仮引数ごしに書き換えるようなことは出来ない


わっかりにくー (-_-;