R: замените шаблон в формуле на имя переменной

#r

#r

Вопрос:

У меня есть общая функция, которая вызывает выражение, использующее формулу, и я хотел бы передать эти функции в различные среды, которые хранят некоторые конкретные переменные и изменяют части формулы, обозначенные определенным шаблоном.

Вот пример:

 # Let's assume I have an environment storing a variable
env <- new.env()
env$..M.. <- "Sepal.Length"

# And a function that calls an expression
func <- function() summary(lm(..M.. ~ Species, data = iris))$r.squared

# And let's assume I am trying to evaluate it within the environment
environment(func) <- env

# And I would like to have some method that makes it evaluate as:
summary(lm(Sepal.Length ~ Species, data = iris))$r.squared
 

До сих пор я придумал очень грязное решение, основанное на преобразовании функции в string, grep, а затем разборе ее обратно. Это выглядит так:

 tfunc <- paste(deparse(func), collapse = "")
tfunc <- gsub("\.\.M\.\.", ..M.., tfunc, perl = TRUE)
tfunc <- eval(parse(text = tfunc))
 

Так что да, это работает, но я хотел бы найти более чистый метод, который каким-то волшебным образом заменил бы этот ..M.. шаблон на Sepal.Length без необходимости всего этого синтаксического анализа и удаления.

Поэтому я был бы очень признателен за помощь и подсказки по этой проблеме.

Комментарии:

1. как, черт возьми, вы здесь оказались

2. Я немного экспериментирую…

3. на ум приходит одна мысль — вставить строку в саму функцию, чтобы заставить это работать: func <- function() summary(lm(..M.. ~ Species, data = iris))$r.squared; expr <- quote(iris$..M.. <- iris$Sepal.Length); body(func) <- as.call(c(list(as.name('{')), list(expr, body(func)))); func()

4. Хм, но это изменяет iris то, что хранится в глобальной среде, верно? Я бы хотел избежать изменения глобальной среды, поскольку это обычно плохая идея.

5. итак, затем удалите часть iris $, это изменяет объекты, созданные внутри функции, если iris и ..M.. не были созданы в функции, тогда это будет выглядеть в глобальном sure quote(..M.. <- iris$Sepal.Length)