П: передача выражения внутренней функции

Углубиться в тайны оценки R ... Это тесно связано с моим предыдущим вопросом ( Как написать функцию R, которая оценивает выражение в кадре данных ]). Допустим, я хочу написать функцию topfn , которая принимает фрейм данных и выражение, включающее имена столбцов этого фрейма данных. Я хочу передать оба этих аргумента другой функции fn , которая фактически оценивает выражение в «среде» фрейма данных. И я хочу, чтобы оба fn и topfn работали правильно при передаче кадра данных и выражения

Моя первая попытка, как было предложено в ответе на вопрос выше , состоит в том, чтобы определить:

 fn <- function(dfr, expr) {
   mf <- match.call()
   eval( mf$expr, envir = dfr )
 }

И определить topfn следующим образом:

topfn <- function(df, ex) {
  mf <- match.call()
  fn(df, mf$ex) 
}

Теперь, если у меня есть фрейм данных

df <- data.frame( a = 1:5, b = 1:5 )

, внутренняя функция fn работает нормально:

> fn(df,a)
[1] 1 2 3 4 5

Но topfn не работает:

> topfn(df,a)
mf$ex

Чтобы исправить это, я сначала проверяю класс topfn (df, a) ,

> class(topfn(df,a))
[1] "call"

Это дает мне представление об уродливом взломе переопределить fn следующим образом:

fn <- function(dfr, expr) {
  mf <- match.call()
  res <- eval(mf$expr, envir = dfr)  
  if(class(res) == 'call')
    eval(expr, envir = dfr) else
  res
}

И теперь обе функции работают:

> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5

Как я уже сказал, это выглядит ужасно. Есть ли лучший способ (или более стандартная идиома) заставить их работать? как предлагается в ответе на вышеупомянутый вопрос, это определить:

 fn <- function(dfr, expr) {
   mf <- match.call()
   eval( mf$expr, envir = dfr )
 }

И определить topfn следующим образом:

topfn <- function(df, ex) {
  mf <- match.call()
  fn(df, mf$ex) 
}

Теперь, если у меня есть фрейм данных

df <- data.frame( a = 1:5, b = 1:5 )

, внутренняя функция fn работает нормально:

> fn(df,a)
[1] 1 2 3 4 5

Но topfn не работает:

> topfn(df,a)
mf$ex

Чтобы исправить это, я сначала проверяю класс topfn (df, a) ,

> class(topfn(df,a))
[1] "call"

Это дает мне идею уродливого хака, чтобы переопределить fn следующим образом:

fn <- function(dfr, expr) {
  mf <- match.call()
  res <- eval(mf$expr, envir = dfr)  
  if(class(res) == 'call')
    eval(expr, envir = dfr) else
  res
}

И теперь обе функции работают:

> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5

Как я уже сказал, это выглядит уродливым хаком. Есть ли лучший способ (или более стандартная идиома) заставить их работать? как предлагается в ответе на вышеупомянутый вопрос, это определить:

 fn <- function(dfr, expr) {
   mf <- match.call()
   eval( mf$expr, envir = dfr )
 }

И определить topfn следующим образом:

topfn <- function(df, ex) {
  mf <- match.call()
  fn(df, mf$ex) 
}

Теперь, если у меня есть фрейм данных

df <- data.frame( a = 1:5, b = 1:5 )

, внутренняя функция fn работает нормально:

> fn(df,a)
[1] 1 2 3 4 5

Но topfn не работает:

> topfn(df,a)
mf$ex

Чтобы исправить это, я сначала проверяю класс topfn (df, a) ,

> class(topfn(df,a))
[1] "call"

Это дает мне идею уродливого хака, чтобы переопределить fn следующим образом:

fn <- function(dfr, expr) {
  mf <- match.call()
  res <- eval(mf$expr, envir = dfr)  
  if(class(res) == 'call')
    eval(expr, envir = dfr) else
  res
}

И теперь обе функции работают:

> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5

Как я уже сказал, это выглядит уродливым хаком. Есть ли лучший способ (или более стандартная идиома) заставить их работать?

> topfn(df,a)
mf$ex

Чтобы исправить это, я сначала проверяю класс topfn (df, a) ,

> class(topfn(df,a))
[1] "call"

Это дает мне идею уродливого хака для переопределения fn следующим образом :

fn <- function(dfr, expr) {
  mf <- match.call()
  res <- eval(mf$expr, envir = dfr)  
  if(class(res) == 'call')
    eval(expr, envir = dfr) else
  res
}

И теперь обе функции работают:

> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5

Как я уже сказал, это выглядит уродливым взломом. Есть ли лучший способ (или более стандартная идиома) заставить их работать?

> topfn(df,a)
mf$ex

Чтобы исправить это, я сначала проверяю класс topfn (df, a) ,

> class(topfn(df,a))
[1] "call"

Это дает мне идею уродливого хака для переопределения fn следующим образом :

fn <- function(dfr, expr) {
  mf <- match.call()
  res <- eval(mf$expr, envir = dfr)  
  if(class(res) == 'call')
    eval(expr, envir = dfr) else
  res
}

И теперь обе функции работают:

> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5

Как я уже сказал, это выглядит уродливым взломом. Есть ли лучший способ (или более стандартная идиома) заставить их работать? Я проконсультировался с документом Lumley с любопытным названием Standard NonStandard Evaluation Rules http://developer.r-project.org/nonstandard-eval.pdf , но после его прочтения не получил особого понимания. Также были бы полезны любые указатели на исходный код функций, которые я могу посмотреть в качестве примеров.

14
задан Community 23 May 2017 в 10:31
поделиться