http://qiita.com/items/325bdf48f4f4885a86f1 と
http://qiita.com/items/35184390984975ec7c6d と
http://qiita.com/items/7fdb523a05a2e0b12f35 の続き。
##1-9 大事な事なので繰り返します。
関数にまつわる3つの環境とは、
- 呼び出し時に作られる環境
- 呼び出し時に作られる環境の親となる環境
- 関数がある環境
です。
普通に使う分には、3は無視していいと思います。1も恒常的なものではないので無視していいと思います。大事なのは関数呼び出しの時の2が何か、を意識しておくことだと思います。
とりあえず関数にまつわる環境の話はこれでいいんだろうか?
なんかよくわかんなかったら教えて下さい。
#2 promise
さて、promise
です。これを説明するためには、遅延評価というものを説明する必要があって面倒なんですが、最近見かける話に、
> f <- function(i) function() i
> r <- lapply(1:3, f)
> r[[1]]()
[1] 3
> r[[3]]()
[1] 3
なんでよー、ちらほらってのがあったので、結構ここで引っかかる人は多いみたいです。
上のr[[1]]()
がなんで3
になるのか即答できる方は読み飛ばしてもらっていいと思います。
#2-1 substituteにまつわる誤解
promise
といえばsubstitute
です。が、これやるにはcall
とかまで行く必要があるので、またこれは別の機会にします。
その代わりにおまけで。
##1-10 環境はリスト
環境はリストです。これほんとです。
> environment()
<environment: R_GlobalEnv> # 隣のおばちゃん
> ls()
character(0) # なんも持ってない
> as.list(.GlobalEnv)
named list() # 空リスト
> a <- 1 # a持っといてー
> ls()
[1] "a" # aある。
> as.list(.GlobalEnv) # aのあるリスト
$a
[1] 1
直感的にリストなら要素の追加できるんじゃね?って思います。
> environment()
<environment: R_GlobalEnv>
> ls()
character(0) # なんも持ってない
> .GlobalEnv$b <- 2 # リストの要素bを追加
> ls()
[1] "b" # あるよ。
> b
[1] 2 # ちゃんとあるよ。
個人的には、関数の中から.GlobalEnv
に値を入れる最もいい方法だと思ってるんですが、この方法がいつまでサポートされるかはわからないので、使わないほうがいいと思います。正しくは、
> ls()
character(0)
> assign("b", 2, .GlobalEnv)
> ls()
[1] "b"
という風に、assign
で環境を指定して値を束縛するのがR風です。
##1-11 <<-
は.GlobalEnv
への代入ではない、という話
グローバル環境の変数に値を束縛するには<<-
を使うというのは巷では有名ですが、これは避けたほうが良いです。X<<-
は、隣のおばちゃんにXがあったらそこに、なかったらそのおばちゃんの相談相手に、そこにもなかったらそのおばちゃんの相談相手に、さいごまでなかったら.GlobalEnv
に、値を代入する、というものです。
> a <- 1 # グローバル環境のaに1
> a
[1] 1
> e <- new.env() # 環境を作成
> e$a <- 1 # その環境にも変数aをおいとく
> e$a
[1] 1
> f <- function() {
+ a <<- 2 # グローバル環境に2を代入する?
+ }
> environment(f) <- e # fの環境をeにしてから
> f() # fを呼び出し
> a
[1] 1 # グローバルのaは変わってなくて、
> e$a
[1] 2 # eのaが変わってる
という感じになるので、絶対にグローバル環境に入れたければ、assign()
を使いましょう。