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

dplyr::mutate内使用rlang::call_args的报错原因与正确用法

提问内容

我在dplyr::mutate中使用rlang::call_args时遇到报错,目前已经找到了不依赖dplyr::mutate的临时解决方案,我想要明确该报错的实际原因,同时学习rlang与dplyr搭配使用的正确方法。

我有一个存储函数调用的单列数据框,示例如下:

df <- tibble::tibble(
  `call` = c(expr(f1(a=1, b=2)), expr(f2(x=5,y=6)), expr(f3(m=9, n=10)))
)

# > df
# # A tibble: 3 x 1
#   call      
#   <list>    
# 1 <language>
# 2 <language>
# 3 <language>

我想要用rlang::call_args生成新列存储每个调用的参数列表,预期输出如下:

# # A tibble: 3 x 2
#  call       args            
#  <list>     <list>          
# 1 <language> <named list [2]>
# 2 <language> <named list [2]>
# 3 <language> <named list [2]>

args列的每一行都是包含对应函数参数的命名列表:

> expected_output$args[[1]]
# $a
# [1] 1

# $b
# [1] 2 

以及:

> expected_output$args[[2]]
# $x
# [1] 5

# $y
# [1] 6 

以此类推。

当我尝试在dplyr::mutate中调用rlang::call_args时,收到报错提示输入不是带引号的调用:

> df %>% mutate(args = rlang::call_args(call))
Error: Problem with `mutate()` input `args`.
x `call` must be a quoted call
ℹ Input `args` is `rlang::call_args(call)`.
Run `rlang::last_error()` to see where the error occurred.
> rlang::last_error()
<error/dplyr:::mutate_error>
Problem with `mutate()` input `args`.
x `call` must be a quoted call
ℹ Input `args` is `rlang::call_args(call)`.
Backtrace:
Run `rlang::last_trace()` to see the full context.
> rlang::last_trace()
<error/dplyr:::mutate_error>
Problem with `mutate()` input `args`.
x `call` must be a quoted call
ℹ Input `args` is `rlang::call_args(call)`.
Backtrace:
     █
  1. ├─df %>% mutate(args = rlang::call_args(call))
  2. ├─dplyr::mutate(., args = rlang::call_args(call))
  3. ├─dplyr:::mutate.data.frame(., args = rlang::call_args(call))
  4. │ └─dplyr:::mutate_cols(.data, ...)
  5. │   ├─base::withCallingHandlers(...)
  6. │   └─mask$eval_all_mutate(dots[[i]])
  7. ├─rlang::call_args(call)
  8. │ └─rlang:::abort_call_input_type("call")
  9. │   └─rlang::abort(sprintf("`%s` must be a quoted call", arg))
 10. │     └─rlang:::signal_abort(cnd)
 11. │       └─base::signalCondition(cnd)
 12. └─(function (e) ...

我已经检查了df$call的元素,确认所有元素都是call对象:

> all(sapply(df$call, rlang::is_call))
# [1] TRUE

我不确定报错信息中的x 'call' must be a quoted call具体含义,我原本认为dplyr::mutate中的函数参数会自动被当作带引号的表达式处理,毕竟我们可以正常运行如下代码而不会报OLDVAR对象不存在的错误:

dplyr::mutate(df, NEWVAR = tolower(OLDVAR))

我已经找到了如下临时解决方案:

> tibble::as_tibble(list(call = df$call, args = lapply(df$call, call_args)))
# # A tibble: 3 x 2
#  call       args            
#  <list>     <list>          
# 1 <language> <named list [2]>
# 2 <language> <named list [2]>
# 3 <language> <named list [2]>

我发起这个提问不是为了寻求该问题的其他解决方法,而是想要清晰理解dplyr::mutate相关报错的根因,学习dplyr与rlang函数搭配使用的正确方式。


回答

报错根本原因

你遇到的报错核心是两个机制叠加导致的:

  1. rlang::call_args 自带非标准评估逻辑:它默认会引用(quote)你传入的第一个参数,不会直接对输入的变量求值。你在mutate中写call_args(call)时,call_args拿到的是call这个列名字符符号本身,而不是call列存储的实际call对象列表,检测到输入不是call对象就直接抛出错误。
  2. rlang::call_args 是单元素处理函数,不支持向量化输入:就算你解决了求值问题,直接把整列的列表向量传给call_args也无法得到逐元素处理的结果,必须配合迭代函数逐行调用。

你之前疑惑的mutate(df, NEWVAR = tolower(OLDVAR))可以正常运行,是因为tolower是普通的向量化函数,没有特殊的引用输入逻辑,会直接对传入的列求值后处理,和call_args的行为逻辑完全不同。

dplyr 与 rlang 搭配的正确用法

针对你的需求,两种符合tidyverse规范的写法如下:

写法1:配合purrr迭代处理

library(dplyr)
library(purrr)

df %>% 
  mutate(args = map(call, rlang::call_args))

map会逐元素取出call列的每个call对象,传给call_args处理,最终返回的结果就是你需要的列表列。

写法2:使用rowwise逐行处理

library(dplyr)

df %>% 
  rowwise() %>% 
  mutate(args = list(rlang::call_args(call))) %>% 
  ungroup()

rowwise会让mutate按行执行,每一行的call都是单个call对象,直接传给call_args处理后用list()包裹,就可以生成符合要求的列表列。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 21:45:08