2014-09-25 13 views
6

Używam następujących skonstruować w opakowaniu,do.call określić środowisko wewnątrz funkcji

## two functions in the global environment 
funa <- function(x) x^2 
funb <- function(x) x^3 
## called within a function, fine 
fun_wrap <- function(){ 
    lapply(c('funa', 'funb'), do.call, list(x=3)) 
} 

fun_wrap() 
[[1]] 
[1] 9 

[[2]] 
[1] 27 

ale ja właśnie został ugryziony przez fakt, że to nie będzie działać, jeśli te funkcje są w sposób różne (lokalny) ramki

## same construct, but the functions are local 
fun_wrap1 <- function(){ 
    funa1 <- function(x) x^2 
    funb1 <- function(x) x^3 
    lapply(c('funa1', 'funb1'), do.call, list(x=3)) 
} 
## now it fails 
fun_wrap1() 
##Error in FUN(c("funa1", "funb1")[[1L]], ...) : 
## could not find function "funa1" 

próbowałem przechodzącą envir=parent.frame(2) do do.call() (nie działa); szczerze strona pomocy ?parent.frame przechodzi przez moją głowę. Jakąkolwiek podpowiedź na bardziej niezawodne użycie do.call?

Zauważ, że lista funkcji pochodzi z wektora znaków, przekazywana z innego fragmentu kodu; Wolę nie przekazywać bezpośrednio funkcji.

Edit: jeden skręt ... Myślałam, że ilustruje właściwą problem z moim przykładzie zabawek, ale rzeczywisty kod używam jest nieco inny, w tym sensie, że dzwonię fun_wrap1 zasięgu oddzielna funkcja. Proponowane rozwiązania zawodzą w tym kontekście.

fun_wrap1 <- function(funs){ 
    lapply(funs, do.call, args=list(x=3), envir=environment()) 
} 

foo <- function(){ 
    funa1 <- function(x) x^2 
    funb1 <- function(x) x^3 
fun_wrap1(c('funa1', 'funb1')) 
} 

foo() 
##Error in FUN(c("funa1", "funb1")[[1L]], ...) : 
## could not find function "funa1" 

(i to samo dzieje się z podejściem match.fun)

mogę zmusić go do pracy przez przekazanie opcjonalnego środowisko fun_wrap1,

fun_wrap1 <- function(funs, e=parent.frame()){ 
    lapply(funs, do.call, args=list(x=3), envir=e) 
} 

foo <- function(){ 
    funa1 <- function(x) x^2 
    funb1 <- function(x) x^3 
    fun_wrap1(c('funa1', 'funb1')) 
} 

foo() 

i mam nadzieję, że to ona.

+0

Przepraszam za ciągłe zmiany, nie udało mi się poprawnie zidentyfikować celu, kiedy napisałem pierwszą iterację. – baptiste

+0

W poprawionym przykładzie, który się nie powiedzie, nowa funkcja powinna zostać zmieniona na: 'fun_wrap1 <- function (funs, envir = parent.frame()) { lapply (funs, do.call, args = list (x = 3) , envir = envir) } 'Funkcja' foo' może pozostać taka jaka jest. –

+0

Dzięki, zmieniłem go zgodnie z twoją radą. – baptiste

Odpowiedz

5

To wydaje się działać, ale nie jestem pewien, czy to ma inne konsekwencje nie jestem rozważenie:

fun_wrap1 <- function(){ 
    funa1 <- function(x) x^2 
    funb1 <- function(x) x^3 
    lapply(c('funa1', 'funb1'), do.call, args=list(x=3), envir=environment()) 
} 

fun_wrap1() 
#[[1]] 
#[1] 9 
# 
#[[2]] 
#[1] 27 

Tak to jest w zasadzie równoważne posiadające oświadczenie lapply jak:

lapply(
     c('funa1', 'funb1'), 
     function(f) do.call(f, args=list(x=3), envir=environment()) 
    ) 
+0

Byłem bardzo gęsty! Umieściłem środowisko na liście obok 'x = 3' ... – baptiste

+0

@baptiste - powinno to być naprawdę" args = list (x = 3) ", aby było naprawdę wyraźne. – thelatemail

2

Oczywiście, jeśli oceniamy funkcje w fun_wrap2, to działa. Problem z podejściem w pytaniu polega na tym, że łańcuchy znaków są konwertowane na funkcje wewnątrz jednej z funkcji przetwarzania, które zmieniają ścieżkę wyszukiwania.

fun_wrap2 <- function(){ 

    funa1 <- function(x) x^2 
    funb1 <- function(x) x^3 

    nms <- c("funa1", "funb1") 
    funs <- lapply(nms, match.fun) 
    lapply(funs, do.call, list(x=3)) 

} 

fun_wrap2() 
+0

ma to sens, dzięki za dodatkowe wyjaśnienie.Od tego czasu zdałem sobie sprawę, że mój problem jest nieco inny i nie mogę uzyskać takiego podejścia do pracy (patrz Edit) – baptiste

+0

, podczas gdy ja naprawdę doceniam pomoc, przyjąłem inną odpowiedź, ponieważ wyjaśniło wyraźne przejście odpowiednie środowisko, które było kluczem do problemu. 'match.fun' osiągnął to samo tutaj, ale być może nie tak wyraźnie. – baptiste

0

Lekko prostsza wersja odpowiedzi @ g-grothendieck. Zamiast używać nazw funkcji, po prostu umieszczamy te funkcje na liście, która jest podawana do lapply.

fun_wrap1 <- function(){ 
    funa1 <- function(x) x^2 
    funb1 <- function(x) x^3 
    lapply(list(funa1, funb1), do.call, list(x=3)) 
} 

fun_wrap1() 
+0

To była moja oryginalna odpowiedź, ale w komentarzach zaznaczył, że dane wejściowe muszą być wektorem znaków nazw, więc zmieniłem je. –