Upload
yatsuta-toshihisa
View
4.096
Download
1
Embed Size (px)
Citation preview
本日の範囲
●2.1.5 Function objects●2.1.8 Promise objects●3.5.1 Global environment●3.5.2 Lexical environment●4 Functions
摩訶不思議な実行結果
funcs <- lapply(1:3,
function(n) {
function () {
n
}
})
> funcs[[1]]() # 3 ???
> funcs[[2]]() # 3 ???
> funcs[[3]]() # 3 ???
顧客が本当に必要だったもの
[ 1 2 3 ]
function(n){function(){n}}
function() {1} function() {2} function() {3}[[ ]]1を返す関数 3を返す関数2を返す関数
今日の役者たち(フレーム、環境)
● フレーム● 束縛(変数名とその値)の表– hash(table), dictionary, 連想配列などをイメージするとよいかも
● 環境● フレームの並び
– Rではframeとenclosureから構成される再帰的構造
x:1y:2z:3
y:7z:8
x:6
y:5
z:9x:4
今日の役者たち(フレーム、環境)
● Eval(x, E1) = 6● Eval(y, E1) = 5● Eval(z, E1) = 3● Eval(w, E1) =error!
x:1y:2z:3
y:7z:8
x:6
y:5
z:9x:4
E1
今日の役者たち(フレーム、環境)
● Eval(x, E2) = 4● Eval(y, E2) = 7● Eval(z, E2) = 8● Eval(w, E2) =error!
x:1y:2z:3
y:7z:8
x:6
y:5
z:9x:4
E2
今日の役者たち(フレーム、環境)
● Eval(x, E3) = 1● Eval(y, E3) = 2● Eval(z, E3) = 9● Eval(w, E3) =error!
x:1y:2z:3
y:7z:8
x:6
y:5
z:9x:4 E3
今日の役者たち(クロージャ)
● クロージャ● コード(関数)と環境(env)へのポインタ– 関数は仮引数(formals)と本体(body)から構成される
...
formals: x, yz = x + yreturn (x + y + z)
function(x, y) { z = x + y return(x + y + z)}
今日の役者たち(プロミス)
● プロミス(promise)● (メモ化付)遅延評価オブジェクト
● 未評価式(expr)、値(value)、環境(env)から構成される
● 関数呼び出しの際、Rによって自動的に生成される。
sqrt(b ** 2 - 4 * a * c)
...
f(sqrt(b ** 2 – 4 * a * c))
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2
formals: x,yz = x + yreturn(x + y + z)
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3y: 3
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3y: 3
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3y: 3
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3y: 3
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3y: 3
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3y: 3z: 6
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3y: 3z: 6
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3y: 3z: 6
例1-1(変数代入、関数定義、関数呼び出し、遅延評価なし)
a = 1b = 2
f = function(x, y) { z = x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz = x + yreturn(x + y + z)
x: 3y: 3z: 6
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:
3
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:
3
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:
3
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:
3
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:
3
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:
33
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:
33
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:
33
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:
33 3
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:
33 3
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:z: 6
33 3
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:z: 6
33 3
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:z: 6
33 3
例1-2(変数代入、関数定義、関数呼び出し、遅延評価あり、つまりR)a <- 1b <- 2
f <- function(x, y) { z <- x + y return(x + y + z)}
f(a+b, 3) # 12
a: 1b: 2f:
formals: x,yz <- x + yreturn(x + y + z)
a+b
x:y:z: 6
33 3
例2-1(オブジェクトもどき、遅延評価なし)
make_acc = function(total) { return (function(n) { total = total + n return(total) })}
a1 = make_acc(10)a1(1) # 11a1(2) # 13
a2 = make_acc(20)a2(1) # 21a2(2) # 23
例2-1(オブジェクトもどき、遅延評価なし)
make_acc = function(total) { return (function(n) { total = total + n return(total) })}
a1 = make_acc(10)a1(1) # 11a1(2) # 13
a2 = make_acc(20)a2(1) # 21a2(2) # 23
formals: totalreturn (function(n) { total = total + n return(total) })
make_acc:
例2-1(オブジェクトもどき、遅延評価なし)
make_acc = function(total) { return (function(n) { total = total + n return(total) })}
a1 = make_acc(10)a1(1) # 11a1(2) # 13
a2 = make_acc(20)a2(1) # 21a2(2) # 23
formals: totalreturn (function(n) { total = total + n return(total) })
make_acc:
formals: ntotal = total + n return(total)
a1:
total: 10
例2-1(オブジェクトもどき、遅延評価なし)
make_acc = function(total) { return (function(n) { total = total + n return(total) })}
a1 = make_acc(10)a1(1) # 11a1(2) # 13
a2 = make_acc(20)a2(1) # 21a2(2) # 23
formals: totalreturn (function(n) { total = total + n return(total) })
make_acc:
formals: ntotal = total + n return(total)
a1:
total: 10→11
n:1
例2-1(オブジェクトもどき、遅延評価なし)
make_acc = function(total) { return (function(n) { total = total + n return(total) })}
a1 = make_acc(10)a1(1) # 11a1(2) # 13
a2 = make_acc(20)a2(1) # 21a2(2) # 23
formals: totalreturn (function(n) { total = total + n return(total) })
make_acc:
formals: ntotal = total + n return(total)
a1:
total: 11→13
n:1 n:2
例2-1(オブジェクトもどき、遅延評価なし)
make_acc = function(total) { return (function(n) { total = total + n return(total) })}
a1 = make_acc(10)a1(1) # 11a1(2) # 13
a2 = make_acc(20)a2(1) # 21a2(2) # 23
formals: totalreturn (function(n) { total = total + n return(total) })
make_acc:
formals: ntotal = total + n return(total)
a1:
total: 13
n:1 n:2
n:1 n:2
total: 20→21→23
a2
a2: a2
例2-2(オブジェクトもどき、遅延評価あり、つまりR)
make.acc <- function(total){ return (function(n) { total <<- total + n return(total) })}
a1 <- make.acc(10)a1(1) # 11a1(2) # 13
a2 <- make.acc(20)a2(1) # 21a2(2) # 23
make.acc:a1:
n: n:
1 1 2 2
formals: totalreturn (function(n) { total <<-total + n return(total) })
total:
10 10
formals: ntotal <<- total + n return(total)
n: n:
1 1 2 2
total: total_a2
20 20
total_a2
a2: a2
a2
g.env
g.env
g.env
g.env g.env
→ 11 → 13
→ 21 → 23
lapplyソースコード探検
> typeof(lapply)
[1] "closure"
> lapply
function (X, FUN, ...)
{
FUN <- match.fun(FUN)
if (!is.vector(X) || is.object(X))
X <- as.list(X)
.Internal(lapply(X, FUN))
}
<environment: namespace:base>
/* from main/apply.c do_lapply() */
for(i = 0; i < n; i++) {
INTEGER(ind)[0] = i + 1;
SET_VECTOR_ELT(ans, i,
eval(R_fcall, rho));
// FUN(XX[[<ind>]], …)
}
lapplyのキモは(Cの)forループ!
摩訶不思議な実行結果(再掲)
funcs <- lapply(1:3,
function(n) {
function () {
n
}
})
> funcs[[1]]() # 3 ???
> funcs[[2]]() # 3 ???
> funcs[[3]]() # 3 ???
lapply実行時の環境
X:1:3 FUN:
ind: 1 → 2 → 3(length(X))
g.env
X[[ind]]
formals: -n
n:
g.env
X[[ind]]
formals: -n
n:
g.env
X[[ind]]
formals: -n
n:
g.env formals: nfunction() { n}
base.env
base.env
(サーチパス)
funcs: …
funcs[[1]] funcs[[2]] funcs[[3]]
lapply実行時の環境
X:1:3 FUN:
ind: 1 → 2 → 3(length(X))
g.env
X[[ind]]
formals: -n
n:
g.env
X[[ind]]
formals: -n
n:
g.env
X[[ind]]
formals: -n
n:
g.env formals: nfunction() { n}
base.env
base.env
(サーチパス)
funcs: …
funcs[[1]] funcs[[2]] funcs[[3]]
すべてのプロミスが評価される前にループが終わっている!
解決策A:クロージャに包む前に強制的に評価
funcs <- lapply(1:3,
function(n) {
n # forcing promise “n”
function () {
n
}
})
> funcs[[1]]() # 1 !!!
> funcs[[2]]() # 2 !!!
> funcs[[3]]() # 3 !!!
解決策A:lapply実行時の環境
X:1:3 FUN:
ind: 1 → 2 → 3(length(X))
g.env
X[[ind]]
formals: -n
n:
g.env
X[[ind]]
formals: -n
n:
g.env
X[[ind]]
formals: -n
n:
g.env formals: nnfunction() { n}
base.env
base.env
(サーチパス)
funcs: …
funcs[[1]] funcs[[2]] funcs[[3]]
1 2 3
解決策B: lapplyの自作
mylapply <- function(x, fun) {
rec <- function(result, x) {
if (length(x) == 0) {
result
} else {
rec(append(result, fun(x[[1]])), x[-1])
}
}
rec(list(), x)
}
● 「ループがダメなら、再帰を使えばいいじゃない」●変数への再代入がないため、遅延評価と相性がよい●参考:Lispのmap(car)関数など
あとは…
● 問題の周知を図る● 「Rでは評価前の関数引数をクロージャに包んで返してはいけない!」
● 問題の根本を解決したとは…
● Cでlapply(非ループ版)を自作● Cを使えば基本何でもできる● 問題の根本を解決したとは…
● なにはともあれ、自衛のため、Rの言語仕様を可能な限り理解しよう!● そんな前向きな貴方にTokyo.Lang.R!
Tokyo.Lang.Rへのお誘い
● The R language definition, R Internals, Writing R Extensionsを輪講形式で読んでいきます。● 順番はThe R language definition → R Internals, 合間に適宜Writing R Extensionsを挟む形にしようと思います。
● 日時は当面Tokyo.R開催日の午前中(10:00-11:45)とします。
● 発表者は当面希望制とします。
● C/C++/Java/Perl/Python/Ruby/Javascript/Rなど、プログラミング言語の使用経験があることを前提とします。
● …
Tokyo.Lang.Rへのお誘い
● http://atnd.org/events/7287 へエントリ!
● @TokyoLangRをフォロー!
ご興味ある方は
よろしくお願いします。
第0回(RプログラマのためのLisp入門、RプログラマのためのAPL入門)絶賛準備中!
おまけ
struct envsxp_struct {
struct SEXPREC *frame;
struct SEXPREC *enclos;
struct SEXPREC *hashtab;
};
struct closxp_struct {
struct SEXPREC *formals;
struct SEXPREC *body;
struct SEXPREC *env;
};
struct promsxp_struct {
struct SEXPREC *value;
struct SEXPREC *expr;
struct SEXPREC *env;
};
typedef enum {
NILSXP = 0,
SYMSXP = 1,
LISTSXP= 2,
CLOSXP = 3,
ENVSXP = 4,
PROMSXP= 5,
...
FUNSXP = 99
} SEXPTYPE;
/*(SEXPRECのヘッダ)*/
struct sxpinfo_struct {
SEXPTYPE type : 5;
...