2015-04-19 8 views
9

Wenn ich eine Funktion wie folgt erstellen:Können Sie die faule Auswertung in R-Funktionsoperatoren deutlicher erklären?

what_is_love <- function(f) { 
    function(...) { 
    cat('f is', f, '\n') 
    } 
} 

Und nennen Sie es mit lapply: funs <- lapply(c('love', 'cherry'), what_is_love)

ich unerwartete Ausgabe:

> funs[[1]]() 
f is cherry 
> funs[[2]]() 
f is cherry 

Aber beachten Sie, dass dies nicht der Fall ist, wenn Sie Verwenden Sie nicht lapply:

> f1 <- what_is_love('love') 
> f2 <- what_is_love('cherry') 
> f1() 
f is love 
> f2() 
f is cherry 

Was gibt?

Ich weiß, dass funs <- lapply(c('love', 'cherry'), what_is_love) mehr geschrieben voll werden kann:

params <- c('love', 'cherry') 
out <- vector('list', length(params)) 
for (i in seq_along(params)) { 
    out[[i]] <- what_is_love(params[[i]]) 
} 
out 

Aber wenn ich in zu sehen, wie ich sehe, dass beide Funktionen ihre eigene Umgebung haben:

Browse[1]> out[[1]] 
function(...) { 
    cat('f is', f, '\n') 
    } 
<environment: 0x109508478> 
Browse[1]> out[[2]] 
function(...) { 
    cat('f is', f, '\n') 
    } 
<environment: 0x1094ff750> 

Aber in jedem dieser Umgebungen, f ist das gleiche ...

Browse[1]> environment(out[[1]])$f 
[1] "cherry" 
Browse[1]> environment(out[[2]])$f 
[1] "cherry" 

ich weiß w die Antwort ist "faule Bewertung", aber ich bin auf der Suche nach etwas mehr Tiefe ... Wie wird f in beiden Umgebungen neu zugeordnet? Woher kommt f? Wie funktioniert R Lazy Evaluation in diesem Beispiel unter der Haube?

-

EDIT: Ich bin mir dessen bewusst the other question auf lazy evaluation und Funktionalen, aber es sagt, nur die Antwort "lazy evaluation" ist, ohne zu erklären, wie die verzögerte Auswertung tatsächlich funktioniert. Ich suche eine größere Tiefe.

+0

möglich Duplikat [Erklären Sie eine faule Auswertung Marotte] (http://stackoverflow.com/questions/16129902/explain-a-lazy-evaluation-quirk) – jangorecki

+1

lapply keine Verhaltensweisen länger auf diese Weise in R-3.2. 0. –

Antwort

11

Wenn Sie das tun

what_is_love <- function(f) { 
    function(...) { 
    cat('f is', f, '\n') 
    } 
} 

die innere Funktion ein Gehäuse für f schafft, aber der Haken ist, dass, bis Sie tatsächlich Verwendung eine Variable an eine Funktion übergeben, es bleibt ein „Versprechen“ und nicht ist tatsächlich ausgewertet. Wenn Sie den aktuellen Wert von f "erfassen" möchten, müssen Sie die Bewertung des Versprechens erzwingen; Sie können dafür die Funktion force() verwenden.

what_is_love <- function(f) { 
    force(f) 
    function(...) { 
    cat('f is', f, '\n') 
    } 
} 
funs <- lapply(c('love', 'cherry'), what_is_love) 

funs[[1]]() 
# f is love 
funs[[2]]() 
# f is cherry 

Ohne force() bleibt f ein Versprechen innerhalb beide Funktionen in Ihrer Liste. Es wird nicht ausgewertet, bis Sie die Funktion aufrufen, und wenn Sie die Funktion aufrufen, wird das Versprechen auf den letzten bekannten Wert für f ausgewertet, der "Kirsche" ist.

Wie @MartinMorgran gezeigt hat, hat sich dieses Verhalten in R 3.2.0 geändert. Aus den release notes

Funktionen höherer Ordnung wie die Funktionen anwenden und reduzieren() nun Argumente Kraft auf die Funktionen, die sie um gelten unerwünschte Wechselwirkungen zwischen lazy evaluation beseitigen und variable Erfassung in Schließungen.Dies löst PR # 16093.

+0

Super, danke für das Detail. Könntest du ein bisschen mehr erklären, wie R verspricht, unter der Haube zu arbeiten? – peterhurford

+0

Sie können nie mit Versprechungen direkt im R-Code arbeiten, denn sobald Sie sie berühren, verschwinden sie. Wenn Sie wissen möchten, wie sie implementiert sind, müssen Sie die [R-Quelle] (https://github.com/wch/r-source) lesen. Es gibt ein bisschen mehr Informationen über sie in Hadleys Diskussion über [Nicht-Standard-Bewertung] ( – MrFlick

+0

) [pryr] (https://github.com/hadley/pryr) Paket, das Funktionen wie 'promise_info()' hat, um Informationen über Versprechen zu extrahieren. – MrFlick

Verwandte Themen