Как использовать дополнительные аргументы purrr :: map (чтобы не повторяться)? - PullRequest
1 голос
/ 01 августа 2020

Я думал, что понял, как использовать аргумент дополнительных аргументов (...) из purrr::map. Вот код, который, надеюсь, иллюстрирует (для меня) неожиданное поведение purrr::map:

Кажется, что передача аргумента a в качестве дополнительного аргумента в purrr::map не работает:

library(purrr)

f <- function(a, b) {
  a + b
}

g <- function(a = 0, b) {
  a + b
}

map(1:3, .f = ~ f(b = .x, a = 1))
#> [[1]]
#> [1] 2
#> 
#> [[2]]
#> [1] 3
#> 
#> [[3]]
#> [1] 4
map(1:3, .f = ~ f(b = .x), a = 1)
#> Error in f(b = .x): argument "a" is missing, with no default

map(1:3, .f = ~ g(b = .x, a = 1))
#> [[1]]
#> [1] 2
#> 
#> [[2]]
#> [1] 3
#> 
#> [[3]]
#> [1] 4
map(1:3, .f = ~ g(b = .x), a = 1)
#> [[1]]
#> [1] 1
#> 
#> [[2]]
#> [1] 2
#> 
#> [[3]]
#> [1] 3

lapply(1:3, function(b, a = 1) f(a, b))
#> [[1]]
#> [1] 2
#> 
#> [[2]]
#> [1] 3
#> 
#> [[3]]
#> [1] 4
lapply(1:3, function(b, a) f(a, b), a = 1)
#> [[1]]
#> [1] 2
#> 
#> [[2]]
#> [1] 3
#> 
#> [[3]]
#> [1] 4

Мой вопрос: почему код:

map(1:3, .f = ~ f(b = .x), a = 1)

выдает ошибку?

Ответы [ 2 ]

2 голосов
/ 01 августа 2020

За кулисами map() вызывает as_mapper () . Мы можем сделать это вручную, чтобы увидеть, что происходит:

purrr::as_mapper( ~ f(b = .x, a = 1) )
# <lambda>
# function (..., .x = ..1, .y = ..2, . = ..1) 
# f(b = .x, a = 1)                                <----
# attr(,"class")
# [1] "rlang_lambda_function" "function"


purrr::as_mapper( ~ f(b = .x), a=1 )
# <lambda>
# function (..., .x = ..1, .y = ..2, . = ..1) 
# f(b = .x)                                       <----
# attr(,"class")
# [1] "rlang_lambda_function" "function"           

Я выделил важное различие с помощью <---. Обратите внимание, что во втором случае создаваемая лямбда-функция не включает ваш дополнительный параметр a=1, что приводит к наблюдаемой вами ошибке.

Чтобы ответить на ваш комментарий, a=1 на самом деле передается лямбда-функции. Ваша лямбда-функция просто ничего с ней не делает. Чтобы правильно включить a, определение лямбда-функции должно обрабатывать ... точек:

g <- function(a, b, ...) {a + b}               # ... are needed to catch all extra 
                                               #   arguments from as_mapper

purrr::as_mapper( .f = ~ g(b=.x, ...) )
# <lambda>
# function (..., .x = ..1, .y = ..2, . = ..1) 
# g(b = .x, ...)                               <-- dots are now forwarded to g()
# attr(,"class")
# [1] "rlang_lambda_function" "function"            

purrr::map(1:3, .f = ~ g(b=.x, ...), a=1 )     # a now properly gets passed to g
# [[1]]
# [1] 2
#
# [[2]]
# [1] 3
#
# [[3]]
# [1] 4
2 голосов
/ 01 августа 2020

Мы могли бы передать оставшиеся аргументы без анонимной функции

library(purrr)
map(1:3, f, a = 1)
#[[1]]
#[1] 2

#[[2]]
#[1] 3

#[[3]]
#[1] 4

Или другой вариант: rlang::as_function или purrr:as_mapper

map(1:3, as_mapper(f), a = 1)

Или создайте f на лету

map(1:3, as_mapper(~ .x + .y), a = 1)

Или назовите его в invoke

map(1:3, ~ invoke(f, b = .x, a = 1))
#[[1]]
#[1] 2

#[[2]]
#[1] 3

#[[3]]
#[1] 4

. Это упростит чтение, чем .f = ~ f(b = .x), a = 1

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