Вложенное использование call_modify - PullRequest
0 голосов
/ 04 октября 2019

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

f <- function(a_call) {
    call_modify(a_call, x=1)
}

a_call <- call2(dbinom, size=1, prob=0.5)
y <- call2(f, a_call)

Вывод для y:

(function(a_call) {
    call_modify(a_call, x=1)
})((function (x, size, prob, log = FALSE) 
.Call(C_dbinom, x, size, prob, log))(size = 1, prob = 0.5))

Этот вызов

  • вызовет a_call безлюбые аргументы, а затем;
  • передают этот результат в f.

Если я оцениваю y, это приводит к ошибкам, поскольку отсутствует первый аргумент dinom.

Я похожа, но связана с конструкцией:

> call2(call2(dbinom, x=1, size=1, prob=0.5))

((function (x, size, prob, log = FALSE) 
.Call(C_dbinom, x, size, prob, log))(x = 1, size = 1, prob = 0.5))()
(function (x, size, prob, log = FALSE) 

Я чувствую, что с тем, что я пытаюсь здесь, есть что-то "даже не то", и лучше всего вложить модификацию вызовасделано по-другому.

Ответы [ 3 ]

1 голос
/ 07 октября 2019

Кажется, что то, что вы пытаетесь сделать, обрабатывается более естественно purrr::partial(), который заполняет один или несколько аргументов функции:

f <- function( a_fun ) {purrr::partial( a_fun, x=1 )}

a_fun <- purrr::partial( dbinom, size=1, prob=0.5 )
y <- f(a_fun)

y(...)теперь эффективно dbinom( x=1, size=1, prob=0.5, ... )

y()            # 0.5
y(log=TRUE)    # -0.6931472

Самое замечательное в partial() заключается в том, что он может быть естественным образом связан с трубой %>%:

z <- partial(dbinom, size=1) %>% partial(prob=0.5) %>% partial(x=1)
z(log=TRUE)    # -0.6931472
0 голосов
/ 06 октября 2019

call2 создает вызов путем передачи оцененных ... аргументов вызываемому объекту (первый аргумент). Например, приведенная ниже команда выводит на консоль "y", поскольку оценивается второй аргумент, передаваемый call2,

> A <- call2(print, x=print('y'))
[1] "y"

и создается вызов print, который принимает x="y" в качестве аргумента(не x=print("y")):

> A
(function (x, ...) 
UseMethod("print"))(x = "y")

Чтобы обойти a_call, который был оценен и затем передан (в f) в построенном вызове, его можно заключить в кавычки, например,

f <- function(a_call) {
    call_modify(a_call, x=1)
}

a_call <- call2(dbinom, size=1, prob=0.5)
y <- call2(f, quote(a_call))

Сейчас:

> y
(function(a_call) {
    call_modify(a_call, x=1)
})(a_call)
0 голосов
/ 05 октября 2019

Если я правильно понимаю, что вы пытаетесь сделать, то, возможно, это работает лучше:

f <- function(a_call) {
  call_modify(call_standardise(call2(ensym(a_call)),
                               caller_env()),
              x=1)
}

Который вы можете использовать с или без символов:

f(print)
# print(x = 1)
f("print")
# print(x = 1)
eval(f(print))
# 1

Или сбольше косвенности:

a_call <- expr(print)
eval(call2(f, a_call))
# print(x = 1)
eval(expr(f(!!a_call)))
# print(x = 1)

Так как здесь мы делаем немного нестандартную оценку, все становится немного сложнее. call_standardise должен быть в состоянии найти указанную вами функцию, и очень вероятно, что она будет найдена в среде, которая вызывает f, и не обязательно в среде, которая вызывает call_standardise, которая будет fСреда исполнения в этом случае. Вот почему caller_env() явно указывается при вызове call_standardise, хотя это значение по умолчанию для последнего env, поскольку аргументы по умолчанию оцениваются в среде выполнения функции, тогда как явные аргументы оцениваются в среде вызывающего.

Вот вычурный пример этой проблемы:

f2 <- function(a_call) {
  call_modify(call_standardise(call2(ensym(a_call))),
              x=1)
}

e <- new.env()
e$foo <- function(x) { x + 1 }
with(e, f(foo))
# foo(x = 1)
with(e, f2(foo))
# Error in eval_bare(node_car(expr), env) : object 'foo' not found

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

Для получения более подробной информации и изображений, проверьте эту ссылку и, возможно, попробуйте нарисовать дерево вызовов длямой пример.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...