Использование строк в качестве аргументов функции - PullRequest
2 голосов
/ 14 февраля 2020

Существует множество вопросов по этой теме c для SO, включая этот вопрос о том, как оценивать выражения, этот , демонстрирующий некоторое несогласие с использованием eval, и этот ответ показывает трюк eval(substitute(.)). Хорошим справочным материалом для изучения нестандартной оценки (NSE) является раздел метапрограммирования Advanced R Хедли Уикхэма. Я отмечаю много разногласий в ответах, причем некоторые сигнализируют о проблемах использования строк в качестве чего-то, что нужно оценивать .

Я нахожусь в таком состоянии использования строки символов в качестве аргумента для дочерняя функция.
Вот пример:

# Consider a little toy function:
little_fun <- function(z = 2, y = 1) {
     (z + 2) / y
}
little_fun()
#> [1] 4

# I can call little_fun() on lists of arguments:
z_list <- c(1,2,3)
purrr::map_dbl(.x = z_list, ~ little_fun(z = (.x)))   # This is basically a tidyverse equivalent for lapply()
#> [1] 3 4 5

# or also:
z_list <- c(1,2,3)
y_list <- c(-1, 0, 1)
purrr::map2_dbl(.x = z_list, .y = y_list, ~ little_fun(z = (.x), y = (.y)))  # again, similar to mapply()
#> [1]  -3 Inf   5

# But I also want to assign the parameters from a more general parent function:
big_fun <- function(par = "y") {

     stopifnot(par %in% c("z", "y"))

     par_list <- c(1,2,3)
     purrr::map_dbl(.x = par_list, ~ little_fun(par = (.x)))   # <--- key line <---
}
big_fun()
#> Error in little_fun(par = (.x)): unused argument (par = (.x))

Моя проблема : я все еще не могу запустить мой код.

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

1 Ответ

3 голосов
/ 14 февраля 2020

Я не согласен с ответом chinsoon12 на ваш вопрос «Стоит ли этого избегать?»

«Защитите себя от будущей глупости» - chinsoon12

Сказав это, динамически назначаемые имена параметров - это одно из мест, где do.call пригодится.

big_fun <- function(par = "y") {
     stopifnot(par %in% c("z", "y"))
     par_list <- c(1,2,3)
     purrr::map_dbl(.x = par_list, ~do.call(little_fun, as.list(setNames(.x, par))))
}

big_fun()
# [1] 4.000000 2.000000 1.333333
big_fun("z")
# [1] 3 4 5

Лично я нахожу, что такое программирование порой изнурительно и проблематично c И у других, пожалуй, единственный способ элегантно решить какую-то проблему. Иногда это наиболее сжатое, надежное и эффективное решение из доступных.

И просто для проверки, я считаю, big_fun() само по себе должно соответствовать этому:

sapply(1:3, little_fun, z=2)
# [1] 4.000000 2.000000 1.333333
...