2012-04-04 7 views
5

Ich versuche, eine Reihe von lapply Aufrufe zu verwenden, um eine Liste der Curry-Funktionen zu erstellen, die idealerweise bei dem letzten Aufruf lapply den endgültigen gewünschten Wert zurückgibt. Das Curry funktioniert, aber lapply scheint immer das letzte Element in der Liste nach der zweiten Anwendung anzuwenden.Warum gehen variable Werte in Closures nach wiederholtem Aufruf von lapply verloren?

Beispiel:

curry <- function(fn, ...) { 
    arglist <- list(...) 
    function(...) { 
    do.call(fn, append(arglist, list(...))) 
    } 
} 
# rcurry is used only to init the first lapply. 
rcurry <- function(v1, fn, ...) { 
    arglist <- append(list(v1), list(...)) 
    function(...) { 
    do.call(fn, append(arglist, list(...))) 
    } 
} 

myadd <- function(a,b,c) { 
    a+b+c 
} 

Dies funktioniert wie erwartet:

# you can achieve the same by closure: 
# curry.a <- lapply(c(10, 1000), FUN = function(a) { curry(myadd, a) }) 
curry.a <- lapply(list(10, 1000), rcurry, myadd) 
curry.a[[1]](1,2) 
curry.a[[2]](1,2) 

# > [1] 13 
# > [1] 1003 

Die nächste lapply von curry "mangles den Umfang":

# this does give the desired output: 
# curry.a.b <- list(curry(curry.a[[1]], 1), curry(curry.a[[2]], 1)) 
curry.a.b <- lapply(curry.a, curry, 1) 
curry.a.b[[1]](2) 
curry.a.b[[2]](2) 

# > [1] 1003 
# > [1] 1003 

Es scheint nicht, wie ein Ergebnis der curry oder rcurry Funktion. Mit roxygenCurry funktioniert die gleiche Funktion. Erstellen durch Schließung oben oder mit curry.a <- list(curry(myadd, 10), curry(myadd, 1000)) ergibt auch das gleiche.

Und die letzte Curry natürlich:

# it doesn't work if you re-define this: 
# curry.a.b <- list(curry(curry.a[[1]], 1), curry(curry.a[[2]], 2)) 
curry.a.b.c <- lapply(curry.a.b, curry, 2) 
lapply(curry.a.b.c, do.call, list()) 

# > [1] 1003 
# > [1] 1003 

Was ist hier los?

+2

'lapply' wertet' FUN' in einer neuen Umgebung. Ich denke, das hat etwas damit zu tun. –

+0

Ich denke, die Antwort ist die gleiche wie in Tommys Antwort auf http://stackoverflow.com/questions/9950144/access-lapply-index-names-inside-fun/9950734#comment12707459_9950734 –

+0

Joshua ist warm, kohske Nägel es. Danke euch allen. –

Antwort

2

fn in curry wird nicht im Funktionsumfang ausgewertet und daher ist es promise. Wenn Sie es force dann können Sie bekommen, was Sie erwarten:

curry <- function(fn, ...) { 
    force(fn) 
    arglist <- list(...) 
    function(...) { 
    do.call(fn, append(arglist, list(...))) 
    } 
} 

dann,

> curry.a.b <- lapply(curry.a, curry, 1) 
> curry.a.b[[1]](2) 
[1] 13 
> curry.a.b[[2]](2) 
[1] 1003 
> 
> curry.a.b.c <- lapply(curry.a.b, curry, 2) 
> lapply(curry.a.b.c, do.call, list()) 
[[1]] 
[1] 13 

[[2]] 
[1] 1003 

Mehr intern, lapply erzeugt eine lokale Variable X, die von jedem Aufruf der Funktion bezeichnet wird. Wenn X nicht in jeder Funktion beim Aufruf der lapply ausgewertet wird, ist X versprochen. Nach dem Aufruf lapply, X in allen Funktionsaufrufen von lapply gibt denselben (d. H. Letzten) Wert zurück. So ist lapply ähnlich mit:

f0 <- function(i) function() i 
f1 <- function(i) {force(i); function() i} 

f <- local({ 
r0 <- list() 
r1 <- list() 
for (i in 1:2) { 
    r0[[i]] <- f0(i) 
    r1[[i]] <- f1(i) 
} 
list(r0 = r0, r1 = r1) 
}) 

dann,

> f$r0[[1]]() 
[1] 2 
> f$r1[[1]]() 
[1] 1 
> f$r0[[2]]() 
[1] 2 
> f$r1[[2]]() 
[1] 2 
+0

100% Bulls Auge. Vielen Dank! Ich dachte eigentlich, dass der Abschluss das Versprechen ist, also habe ich 'closure <- function (...) {do.call (fn, append (Liste, (...))}; force (closure); return closure' Natürlich hat das nicht funktioniert. –