在地图中使用局部

Using partial within map

我遇到了一个有趣的问题。我有一个包含三个变量的函数,假设(为了简单和透明)它是这样的:

my_fun <- function(a, b, c) paste(a, b, c, sep = '-')

我想为 ab 的几种组合创建仅具有参数 c 的多个函数。我正在使用函数 map2partial(均来自包 purrr)。

require(purrr)
funs <- map2(letters[1:5], LETTERS[1:5], partial, ...f = my_fun)

我希望函数列表中的每个函数产生不同的输出,但事实并非如此。

funs[[1]]('hi')    # [1] "e-E-hi"
funs[[3]]('hi')    # [1] "e-E-hi"
funs[[5]]('hi')    # [1] "e-E-hi"

我可以为我的问题创建不同的解决方案,所以我的问题不是 "how to do it"。我对它为什么这样做很感兴趣。


另一个使用基数的例子mapply:

mapply(partial, letters[1:5], LETTERS[1:5], MoreArgs = list(...f = my_fun))[[1]]('hi')
# [1] "e-E-hi"

问题源于 partial 使用惰性求值,在 map2 内意味着它存储 .x.y 而不是 aA。幸运的是有一个函数参数,我们可以使用:

funs <- map2(letters[1:5], LETTERS[1:5], partial, ...f = my_fun, .lazy = FALSE)

funs[[1]]('hi')
# [1] "a-A-hi"

如果您查看您的版本,我们会看到:

funs[[1]]

# function (...) 
# my_fun(.x[[i]], .y[[i]], ...)
# <environment: 0x00000000201d9598>

其他 4 个都一样。

现在,如果我们查看那个环境,我们可以看到:

ls(envir = environment(funs[[1]]))
# [1] "i"

所以那里存储了一个对象i,它将决定我们得到哪个.x.y,它的值是:

get('i', environment(funs[[1]]))
# [1] 5

另请注意,您的参数也存储在那里,但由于它们以 .:

开头而被隐藏
ls(envir =     environment(funs[[1]]), all.names = TRUE)
# [1] "..." ".f"  ".x"  ".y"  "i" 
get('.x', envir = environment(funs[[1]]))
# [1] "a" "b" "c" "d" "e"

所以对于所有这些,我们得到相同的结果。具体来说,执行的调用最终是:

my_fun(letters[1:5][[5]], LETTERS[1:5][[5]], 'hi')

惰性求值在这里不是很好,并且使用了 map2 中存储的内部循环计数器。