Определите анонимную функцию без использования ключевого слова `function` - PullRequest
0 голосов
/ 25 сентября 2018

Я могу определить и использовать анонимную функцию и вызывать ее так:

x <- 1:3
sapply(x, function(x) x)

Иногда я чувствую, что использование такой функции слишком многословно.Есть ли другой способ определения анонимной функции?

В пакете purrr можно определить анонимную функцию, такую ​​как

map(x, ~.x)

, но это работает только в контексте purrr.

Ответы [ 5 ]

0 голосов
/ 26 сентября 2018
  • Функция pryr::f допускает очень компактные определения функций, она угадывает аргументы функции из выражения, которое вы ей передаете, она хорошо работает для простых вызовов.
  • purrr используетpurrr::as_mapper, который сам по себе вызывает rlang::as_function, так что вы также можете вызывать их, хотя и не намного более многословно.
  • Я написал пакет с именем lambda , который делает совместимость нотаций формулс базой R (или любым пакетом с незначительной настройкой), он находится в процессе, но уже полностью пригоден для использования.Только для интерактивного использования, не программируйте с ним.

примеры:

f

aggregate(. ~ Species, iris, pryr::f(mean(range(.))))
#      Species Sepal.Length Sepal.Width Petal.Length Petal.Width
# 1     setosa         5.05        3.35         1.45        0.35
# 2 versicolor         5.95        2.70         4.05        1.40
# 3  virginica         6.40        3.00         5.70        1.95

as_function

aggregate(. ~ Species, iris, rlang::as_function(~mean(range(.))))
#      Species Sepal.Length Sepal.Width Petal.Length Petal.Width
# 1     setosa         5.05        3.35         1.45        0.35
# 2 versicolor         5.95        2.70         4.05        1.40
# 3  virginica         6.40        3.00         5.70        1.95

Вы можете присвоить его короткой переменной для компактного синтаксиса:

.. <- rlang::as_function
aggregate(. ~ Species, iris, ..(~mean(range(.))))

as_mapper

aggregate(. ~ Species, iris, purrr::as_mapper(~mean(range(.))))
#      Species Sepal.Length Sepal.Width Petal.Length Petal.Width
# 1     setosa         5.05        3.35         1.45        0.35
# 2 versicolor         5.95        2.70         4.05        1.40
# 3  virginica         6.40        3.00         5.70        1.95

lambda

# devtools::install_github("moodymudskipper/lambda")
library(lambda)
attach_lambda()
aggregate(. ~ Species, iris, ~mean(range(.)))
#      Species Sepal.Length Sepal.Width Petal.Length Petal.Width
# 1     setosa         5.05        3.35         1.45        0.35
# 2 versicolor         5.95        2.70         4.05        1.40
# 3  virginica         6.40        3.00         5.70        1.95

Дополнительные функции, такие как base::Negate, base::vectorize, purrr::partial, purrr::compose ... могут иногда помочь сделать код более компактным.

0 голосов
/ 25 сентября 2018

Я уверен, что любой здравомыслящий R-программист должен серьезно обидеться за следующее, но для забавы это, похоже, сработает и избавит от рутинной необходимости вызова функции длиной 6 букв

s=function(x,f)
{
    eval(parse(text = paste('y <- function(x)',deparse(substitute(f)),collapse='')))
    sapply(x,y)
}

Так что теперь s используется вместо sapply.

s(1:3,x*2)
## [1] 2 4 6

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

0 голосов
/ 25 сентября 2018

1) gsubfn :: fn Пакет gsubfn поддерживает формулу для определения функций и, в отличие от purrr, упомянутого в вопросе, работает только с функциями purrr, с которыми он работает толькоо любой функции.

Если анонимная функция передается другой функции, в примере анонимная функция передается sapply, затем предисловие sapply с fn$ и использование формульной записи формы args ~ body.Если аргументы отсутствуют, предполагается, что свободные переменные в теле являются аргументами в том порядке, в котором они встречаются в теле, поэтому в первом примере ниже z предполагается в качестве единственного аргумента.

library(gsubfn)

x <- 1:3
fn$sapply(x, ~ z)
## [1] 1 2 3

# same - specify arg
fn$sapply(x, z ~ z)
## [1] 1 2 3

# same - can use any variable name we like
fn$sapply(x, ~ x)
## [1] 1 2 3

# same
sapply(x, function(z) z)
## [1] 1 2 3

Анонимные функции могут иметь любое количество аргументов.Следующие элементы одинаковы:

fn$sapply(x, ~ u + 2 * v, v = 10)
## [1] 21 22 23

# same
fn$sapply(x, u + v ~ u + 2 * v, v = 10)
## [1] 21 22 23

# same
sapply(x, function(u, v) u + 2 * v, v = 10)
## [1] 21 22 23

2) magrittr

Пакет magrittr поддерживает конвейерную нотацию для определения функций с одним аргументом.Аргумент должен быть точкой.

library(magrittr)

x <- 1:3
sapply(x, . %>% {.})
## [1] 1 2 3

# same
sapply(x, function(x) x)
## [1] 1 2 3

# same
x %>% sapply(. %>% {.})
## [1] 1 2 3

3) lambda.r Пакет lambda.r позволяет определять именованные функции, используя%as%.Здесь мы определяем функцию с именем fun.

library(lambda.r)

x <- 1:3
fun(x) %as% x
sapply(x, fun)
## [1] 1 2 3

# same
fun <- function(x) x
sapply(x, fun)
## [1] 1 2 3
0 голосов
/ 25 сентября 2018

Пакет 'wrapr' предоставляет несколько способов сокращения анонимных функций.На платформе LINUX (в зависимости от ОС и локали лямбда-символ может быть «буквой», доступной для именования символа), вы можете выполнять следующие действия:

library(wrapr)
λ <- lambda
sapply(1:10,λ(x,x^2))
#[1]   1   4   9  16  25  36  49  64  81 100

λ(x,y,x*y)(6,7)
#[1] 42
0 голосов
/ 25 сентября 2018

Насколько менее многословным вы могли бы это сделать?Вам нужен какой-то индикатор того, что это функция, какой-то способ сказать аргументы и какой-то способ вычисления.Единственное, что делает его «многословным», - это то, что «функция» имеет восемь букв.Если вы не хотите этого, тогда определите вашу функцию вне , а затем получите sapply(x, foo), которое является кратким, описательным и понятным без обращения к внешним зависимостям (purrrr) или нестандартной оценке.

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