79
Rの失敗? 環境と変数代入と遅延評価と ~R Language Definition案内#2~ Tokyo.R #09 2010/09/19 id:(t)yatsuta

100919 tokyor

Embed Size (px)

Citation preview

Rの失敗?環境と変数代入と遅延評価と

~R Language Definition案内#2~

Tokyo.R #092010/09/19id:(t)yatsuta

本日の範囲

●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を返す関数

本日の参考資料

● SICP● 計算機プログラムの構造と解釈

● 英語版はオンラインで無料で読めます。

● この資料の表記法はSICPの表記法を参考(ほぼパクリ)にしています。

今日の役者たち(フレーム、環境)

● フレーム● 束縛(変数名とその値)の表– 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

でも…

● Rの言語仕様に合わせて関数を書き換えるのは● 面倒● 悔しい● 他の言語使いにバカにされるかもしれないし…● 後継者が修正(エンバグ)しちゃうかもしれないし…

● じゃあどうする?

解決策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;

...