2016-12-11 8 views
0

Я хочу написать функцию в R, которая захватывает имя переменной из контекста вызывающего абонента. Я думаю, что проблема, которую я имею, лучше понять, спросив, как составить deparse и substitute. Вы можете видеть, что наивная композиция не работает:В R, как определить функцию, эквивалентную `deparse (substitute (x))`?

# a compose operator 
> `%c%` = function(x,y)function(...)x(y(...)) 

# a naive attempt to combine deparse and substitute 
> desub = deparse %c% substitute 
> f=function(foo) { message(desub(foo)) } 
> f(log) 
foo 

# this is how it is supposed to work 
> g=function(foo) { message(deparse(substitute(foo))) } 
> g(log) 
log 

Я также попробовал несколько вариаций, связанных с eval.parent, но не повезло. Любая помощь приветствуется.


Разъяснение: Я не ищу синоним deparse(substitute(...)), например, match.call()[[2]] - то, что я ищу способ определить функцию

desub = function(foo) { 
    ... 
    # What goes here? 
} 

таким образом, что определение f выше дает тот же ответ, как g. Он должен выглядеть следующим образом:

> f=function(foo) { message(desub(foo)) } 
> f(log) 
log 

Возможно match.call может быть полезным в теле desub выше, но я хотел бы знать, каким образом. Благодаря!

+0

Вы можете проверить 'match.call' – akrun

+0

@akrun: Я знаю о' match.call', но я не вижу, как это поможет. Вы хотите немного разобраться? Или, может быть, вам будет проще всего предоставить строку кода, которая делает то, о чем я прошу ... – Metamorphic

+0

Я имел в виду соответствие 'g1 <- function (foo).называть() [[2]]; g1 (log) # log' – akrun

ответ

1

Благодаря @ egnha и @akrun для смелых попыток. Немного поиграв, я нашел решение, которое работает.

Этот фрагмент:

desub <- function(y) { 
    e1=substitute(y) 
    e2=do.call(substitute,list(e1), env=parent.frame()) 
    deparse(e2) 
} 

дает:

> f <- function(x) message(desub(x)) 
> f(log) 
log 

Update:

С помощью Марка Bravington на R-разви список, я был в состоянии обобщить это к нескольким кадрам. Я думал, что должен опубликовать его здесь, потому что это немного более полезно, чем выше, и потому, что в было сложное обходное решение, связанное с (возможно, ошибкой?).

# desub(v,0)=="v" 
# desub(v,1)==deparse(substitute(v)) 
# desub(v,2)==name of v in grandparent's frame 
# etc. 
desub = function(y,n=1) { 
    env=environment(); 
    for(i in 0:n) { 
    y = do.call(substitute, list(substitute(y)), env=env) 
    env = do.call(my_mvb_parent, list(), env=env) 
    } 
    deparse(y) 
} 

# helper: 
# 
# - using mvb.parent.frame fixes problems with capture.output and 
# weird cycling behavior in the built-in parent.frame 
# 
# - this wrapper makes mvb.parent.frame not throw an error when we get 
# to globalenv() 
my_mvb_parent=function() { 
    library(mvbutils) 
    tryCatch(
    mvb.parent.frame(2), 
    error=function(e) { globalenv()}) 
} 

if(1) { 
    # example code 
    g2=function(t) { 
    for(i in 0:5) { 
     res=desub(t,i); 
     print(res); 
     res1=capture.output(desub(t,i)) 
     stopifnot(capture.output(res)==res1) 
    } 
    } 
    g1=function(z) g2(z) 
    g=function(y) g1(y) 
    g(log) 
    # prints: 
    ## [1] "t" 
    ## [1] "z" 
    ## [1] "y" 
    ## [1] "log" 
    ## [1] "log" 
    ## [1] "log" 
} 
2

Как вы догадались, это проблема с окружающей средой. Причина, по которой функция f не дает log, когда вы вызываете f(log), является то, что среда, в которой вызывается substitute, а именно среда оценки desub, не содержит привязки к log.

Лекарство оценить вызов substitute в соответствующей среде, и изменять desub соответственно:

desub <- function(x, env = parent.frame()) { 
    deparse(eval(substitute(substitute(x)), envir = env)) 
} 

Теперь f делает то, что он должен был сделать:

f(log) 
#> log 
+0

egnha: Спасибо, прежде чем принять его, не возражаете ли вы редактировать свой ответ, чтобы предоставить код для «# Что здесь происходит?»? – Metamorphic

+0

Кроме того, ваш ответ зависит от аргумента 'f_new' от имени' x'. Если вы измените его на 'y', ваша программа напечатает' x' ... – Metamorphic

+0

@Metamorphic Вы правы. Это поведение согласуется с аргументами, которые я дал. Тем не менее, ваша вариация моего решения более точно решает исходную проблему. Я обновлю. – egnha