Я хочу создать функцию, которая возвращает другую функцию с параметром из первой, например.
foo1 <- function(y) function(x) x+y
(Обновлено: изначально я написал foo1 <- function(y) function(x+y)
, изменил это. Также см. ответ @Konrad Rudolph о том, почему это плохое определение.)
но! Я хотел бы увидеть, какое значение параметра «y» было выбрано. Вышеупомянутое печатает как
foo1(1.2)
#> function(x) x + y
#> <environment: 0x000001dd24275a90>
Теперь я мог бы добиться этого через
foo2 <- function(y){
eval(parse(text = sprintf("function(x) x + %s", y)))
}
Затем печать «foo2» показывает, какое значение параметра «y» использовалось при его создании.
foo2(1.2)
#> function(x) x + 1.2
#> <environment: 0x000001dd242604a0>
Однако я подозреваю, что есть более элегантное решение.
Я думал что-то вроде
foo3 <- function(y){
eval(substitute(function(x) x+dummy, env = list(dummy=y)))
}
могло бы сработать, но нет. Это будет напечатано
foo3(1.2)
#> function(x) x+dummy
#> <environment: 0x000001dd23e137d0>
Есть ли у кого-нибудь более элегантное решение, чем мой «foo2»?
Прежде всего, помните, что ваша исходная функция не работает (помимо синтаксической ошибки):
foo1 <- function(y) function(x) x+y
a <- 10
myfoo <- foo1(a)
a <- 20
myfoo(1)
# [1] 21
Вероятно, вы хотели, чтобы последний вызов возвращал 11, а не 21.
Чтобы это исправить, нам нужно принудительно выполнить нетерпеливую оценку y
— иначе она будет лениво оцениваться при использовании, а не раньше:
foo1 <- function (y) {
force(y)
function (x) x + y
}
Далее, чтобы ответить на ваш актуальный вопрос: ваш foo3
почти работает! R просто обманывает вас, потому что он хранит «исходный код» функции в атрибуте (srcref
) функции. И при отображении определения функции через print
он печатает это srcref
(если доступно) вместо фактического тела. Мы можем удалить атрибут, чтобы исправить это:
foo <- function (y) {
fun <- eval(substitute(function(x) x + dummy, env = list(dummy = y)))
attr(fun, 'srcref') <- NULL
fun
}
foo(1.2)
# x + 1.2
# <environment: 0x108952138>
(Обратите внимание, что нам не нужно явно принудительно вычислять y
в этом определении foo()
, поскольку передача его в list()
(а затем в substitute()
) все равно приведет к его вычислению.)
@HenrikRenlund О да, опечатка! На самом деле я исправил это в своем коде (я проверяю код перед публикацией!), но забыл обновить сообщение.
@SamR Думаю, вы, вероятно, уже ознакомились с определением print.function
, но если вы еще этого не сделали, посмотрите также разницу между print(foo3(1))
и print(foo3(1), useSource = FALSE)
(используя определение foo3
, данное ОП).
Увлекательно - так что вы могли бы сохранить определение foo3
таким же, как в версии @HenrikRenlund, и заставить R всегда печатать функции таким образом, например print.function <- function(x) print.default(x, useSource = FALSE)
. Или, если вы не хотите менять поведение печати всех функций, вместо установки атрибута "srcref"
на NULL
вы можете сделать class(fn) <- "printliteral"
внутри своей функции и определить print.printliteral <- function(x) print.default(x, useSource = FALSE)
. Интересная штука.
@KonradRudolph ой, я пропустил строчку, когда читал. Извините за этот вопрос
Это решение прекрасно работает! Хотя мне придется использовать 'attr(fun, "srcref") <- NULL' (может быть, это решит проблему и для @SamR?). Спасибо за этот ответ - очень познавательно