2013-05-01 11 views
9

próbowałem realizuje funkcję let z następujących semantyki:match.call zwany w niewłaściwym środowisku kiedy eval'ing

> let(x = 1, y = 2, x + y) 
[1] 3 

... co jest koncepcyjnie nieco podobny do substitute ze składni with.

Następujący kod prawie działa (powyższy wywołanie na przykład prace)

let <- function (...) { 
    args <- match.call(expand.dots = FALSE)$`...` 
    expr <- args[[length(args)]] 
    eval(expr, 
     list2env(lapply(args[-length(args)], eval), parent = parent.frame())) 
} 

Uwaga zagnieżdżony eval zewnętrzna ocenić faktycznej ekspresji i wewnętrznego do oceny argumentów.

Niestety, ta ostatnia ocena dzieje się w niewłaściwym kontekście. Staje się to oczywiste, gdy próbuje zadzwonić let z funkcją, która analizuje bieżącą klatkę, takich jak match.call:

> (function() let(x = match.call(), x))() 
Error in match.call() : 
    unable to find a closure from within which 'match.call' was called 

myślałem o dostarczanie ramki nadrzędnej jako środowiska oceniającego dla eval, ale to nie działa:

let <- function (...) { 
    args <- match.call(expand.dots = FALSE)$`...` 
    expr <- args[[length(args)]] 
    parent <- parent.frame() 
    eval(expr, 
     list2env(lapply(args[-length(args)], function(x) eval(x, parent)), 
        parent = parent) 
} 

Powoduje to ten sam błąd. Co prowadzi mnie do pytania: jak dokładnie oceniono match.call? Dlaczego to nie działa? I, jak to zrobić?

+0

Możliwe, że jest to istotne z '? Match.call':" Wywołanie "match.call" poza funkcją bez określenia "definicji" jest błędem. " A następnie spróbuj 'j <- function (x) x; j (match.call()) ', aby zobaczyć jedno miejsce, w którym wystąpił błąd. Nie rozgrywałam tego wszystkiego (i nie całkiem rozumiem, co naprawdę chcesz zrobić), ale może to być błąd, który jest specyficzny dla dziwnego sposobu używania 'match.call()' w to połączenie z anonimową funkcją. –

+0

@Josh Nie sądzę, że jest to powiązane. Komunikat o błędzie jest inny, a kontekst, w którym nazywam 'match.call' jest * zdecydowanie * z wewnątrz funkcji, jeśli jest zły. –

+0

Domyślam się, że sugerowałem, że 'match.call()' ma dość unikatowe reguły dotyczące zasięgu, które okazują się być specjalnie okablowane dla niego na poziomie C. (Kod definiujący 'do_matchcall', zawierający kilka interesujących komentarzy na temat tego, jak funkcja jest wywoływana, jest zapisany, jest w' $ R_SRC/src/main/unique.c'.) W przeciwieństwie do prawie każdej innej funkcji, nie jest dla mnie jasne, że to środowisko ewaluacyjne może być manipulowane/ustawiane przez wywołanie 'eval()'. Aby uprościć twój problem, może najpierw zorientuj się, dlaczego to nie działa (i jak można to zrobić): 'j <- function() eval (call (" match.call ")); j() '. –

Odpowiedz

6

Czy to przepisanie rozwiąże problem?

let <- function (expr, ...) { 
    expr <- match.call(expand.dots = FALSE)$expr 
    given <- list(...) 
    eval(expr, list2env(given, parent = parent.frame())) 
} 

let(x = 1, y = 2, x + y) 
# [1] 3 
+0

+1 - Ciekawe, że 'match.call (expand.dots = FALSE) $" ... "' i 'list (...)' zwracają różne obiekty. –

+0

Argumenty są w złej kolejności tutaj, a jednak wydaje się, że działa. Czy możesz wyjaśnić ** dlaczego ** to działa? To znaczy. dlaczego możemy przekazać wyrażenie jako argument * last * i nadal go przypisujemy do pierwszego? To powiedziawszy, to wyrażenie ma pierwszy problem jako moje pierwsze podejście, ponieważ nie przechwytuje nadrzędnego zakresu ... musisz jawnie przekazać 'rodzic = rodzic.frame() 'to' list2env', mimo że jest to domyślna wartość parametru, w przeciwnym razie to nie zadziała: '(funkcja (x) let (y = 2, x + y)) (1)' –

+2

@KonradRudolph - To tylko konsekwencja lub [zasady R/algorytm dopasowywania argumentów] (http://stat.ethz.ch/R-manual/R-devel/doc/manual/R-lang.html#Argument-matching). Najpierw przetwarzane są nazwane argumenty (tutaj 'x = 1' i' y = 2'), a żadna z nich nie ma nazwy pasującej do nazwy o nazwie formalny ('wyr '). Następnie, jak wspomniano w powyższym linku "Wszelkie niedopasowane argumenty formalne są związane z nienazwanymi podanymi argumentami, w kolejności". Tutaj oznacza to, że 'x + y' jest przywiązany do' wyraż. '. –

Powiązane problemy