You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

purrr::pmap与rlang配合的混淆行为:参数是否需引号?

问题解答

1. 为什么pmap不带引号时会报错?

这本质是求值环境与非标准求值(NSE)的冲突:

  • 你的tryfn用rlang::enquo()捕捉参数的表达式和调用环境,当直接调用tryfn(iris, Sepal.Length, Sepal.Width)时,Sepal.Length是在函数调用的上下文里被捕捉的,dplyr的NSE机制会自动在传入的data(也就是iris)环境中解析这个符号,所以能找到对应的列。
  • 但在pmap里,你写list(Sepal.Length, wt, len)时,R会立即在全局环境中尝试求值这些变量名——而Sepal.Length是iris的列,不是全局环境里的独立对象,所以自然会抛出“找不到对象”的错误。
  • 当你传带引号的字符串时,这些是字面量,在全局环境中是合法的对象,pmap可以正常传递,而enquo()捕捉到字符串表达式后,dplyr的select()可以直接解析字符串作为列名,所以能正常工作。

2. 如何让函数在pmap中无需引号也能运行?

这里有几种简洁的解决方案,核心思路是让参数以符号/quosure对象的形式传递,避免在全局环境中提前求值:

方案1:用rlang::ensym()改造函数,兼容符号与字符串

ensym()可以自动把输入的符号或字符串转换成符号,让函数同时支持两种输入方式,且适配pmap的调用:

library(rlang)
library(dplyr)
library(purrr)

tryfn <- function(data, x, y) {
  # 将输入转换为符号
  x <- ensym(x)
  y <- ensym(y)
  
  data <- select(
    .data = data,
    x = !!x,
    y = !!y
  )
  
  data.frame(mean.x = mean(data$x), mean.y = mean(data$y))
}

# pmap调用时传递符号对象(用sym()创建)
pmap(.l = list(
  data = list(iris, mtcars, ToothGrowth),
  x = list(sym("Sepal.Length"), sym("wt"), sym("len")),
  y = list(sym("Sepal.Width"), sym("mpg"), sym("dose"))
), .f = tryfn)

也可以用quote()直接创建符号,写法更简洁:

pmap(.l = list(
  data = list(iris, mtcars, ToothGrowth),
  x = list(quote(Sepal.Length), quote(wt), quote(len)),
  y = list(quote(Sepal.Width), quote(mpg), quote(dose))
), .f = tryfn)

方案2:用curly-curly语法简化函数

dplyr 1.0.0+支持的{{ }}语法可以替代enquo()+!!的组合,让函数代码更简洁,同时保持兼容性:

tryfn <- function(data, x, y) {
  data <- select(
    .data = data,
    x = {{x}},
    y = {{y}}
  )
  
  data.frame(mean.x = mean(data$x), mean.y = mean(data$y))
}

# 调用方式和方案1完全一致
pmap(.l = list(
  data = list(iris, mtcars, ToothGrowth),
  x = list(quote(Sepal.Length), quote(wt), quote(len)),
  y = list(quote(Sepal.Width), quote(mpg), quote(dose))
), .f = tryfn)

方案3:传递quosure对象(无需修改原函数)

如果你不想改动原函数,可以在pmap里直接传递quosure对象,让enquo()能正确捕捉到表达式的解析环境:

pmap(.l = list(
  data = list(iris, mtcars, ToothGrowth),
  x = list(quo(Sepal.Length), quo(wt), quo(len)),
  y = list(quo(Sepal.Width), quo(mpg), quo(dose))
), .f = tryfn)

内容的提问来源于stack exchange,提问作者Indrajeet Patil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:19:19