Функция передается как аргумент функции. Проблема связана с:
::
и :::
Функция fun_tst
выполняет функцию FUN
на x:
fun_tst <- function(x = 1:100, FUN = mean) {
return(FUN(x))
}
mean
fun_tst()
# [1] 50.5
sum
fun_tst(x = 1:1e3, FUN = sum)
# [1] 500500
fun_tst <- function(x = 1:100, FUN = mean) {
msg <- paste("Executing function", FUN)
print(msg)
return(FUN(x))
}
fun_tst(x = 1:1e3, FUN = sum)
Error in paste("Executing function", FUN) : cannot coerce type 'builtin' to vector of type 'character'
Интересно, что print
может обрабатывать объект FUN
, но результаты возвращают тело функции.
fun_tst <- function(x = 1:100, FUN = mean) {
print(FUN)
return(FUN(x))
}
fun_tst(x = 1:1e3, FUN = sum)
function (..., na.rm = FALSE) .Primitive("sum") [1] 500500
subsitute
fun_tst <- function(x = 1:100, FUN = mean) {
fun_name <- substitute(FUN)
msg <- paste("Executing function", fun_name, collapse = " ")
print(msg)
return(FUN(x))
}
fun_tst(x = 1:1e3, FUN = sum)
>> fun_tst(x = 1:1e3, FUN = sum)
[1] "Executing function sum"
[1] 500500
Почти готово, но похоже на полный беспорядок при использовании с ::
, как в:
>> fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
[1] "Executing function :: Executing function dplyr Executing function glimpse"
int [1:1000] 1 2 3 4 5 6 7 8 9 10 ..
fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
# Executing function glimpse from package dplyr
int [1:1000] 1 2 3 4 5 6 7 8 9 10 ...
fun_tst(x = 1:1e3, FUN = sum)
# Executing function sum from package base
Другой вариант - передать имя функции как символ, распечатать имя, а затем использовать eval
и parse
для вызова функции.
@Frank Спасибо, звучит как разумное предложение. Я надеюсь, что, возможно, есть простой способ «выловить» пространство имен функции (пакет) и его имя без разборки, а затем снова проанализировать ....
Вы почти у цели со второй попыткой (с использованием substitute
). Проблема возникает из-за того, как R преобразует объекты language
в символы:
> as.character(substitute(dplyr::glimpse))
[1] "::" "dplyr" "glimpse"
Учитывая это, неудивительно, что paste
искажает это таким образом. Я бы исправил это, просто обработав два случая отдельно:
fun_tst <- function(x = 1:100, FUN = mean) {
fun_name <- substitute(FUN)
if (length(fun_name) == 1) {
msg <- paste("Executing function", fun_name, "from package base")
} else {
msg <- paste("Executing function", fun_name[3], "from package", fun_name[2])
}
print(msg)
return(FUN(x))
}
Это работает в обоих ваших примерах:
> fun_tst(x = 1:1e3, FUN = sum)
[1] "Executing function sum from package base"
[1] 500500
> fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
[1] "Executing function glimpse from package dplyr"
int [1:1000] 1 2 3 4 5 6 7 8 9 10 ...
Однако, как написано, он будет думать, что все функции в глобальной среде взяты из base
, даже если они определены пользователем или введены с помощью вызова library
. Если это ваш вариант использования, не говорите явно «из пакета».
Если вы используете deparse()
и substitute
, вы получите желаемый результат, см. Аналогичный пост о передаче имен переменных в plot()
, https://stackoverflow.com/a/9666650/1993932.
fun_tst <- function(x = 1:100, FUN = mean) {
message(paste("Executing function",deparse(substitute(FUN))))
return((FUN(x)))
}
> fun_tst(x = 1:1e3, FUN = sum)
Executing function sum
[1] 500500
> fun_tst(x = 1:1e3, FUN = dplyr::glimpse)
Executing function dplyr::glimpse
int [1:1000] 1 2 3 4 5 6 7 8 9 10 ...
Если вы предпочитаете, чтобы сообщение было векторным символом, замените message
на print
.
возможно актуально: "Как узнать название текущей функции?" и stackoverflow.com/questions/7307987/…