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

如何向bench::mark的exprs参数传递批量生成的表达式?

如何自动生成适配bench::mark的表达式列表?

问题背景

首先定义一个包含多个函数的列表:

funcs <- list(
  loop = function(n) {
    result <- 0
    for (i in seq_len(n)) {
      result <- result + i
    }
    result
  },
  vect = function(n) sum(seq_len(n))
)

手动编写每个函数的调用表达式传入bench::mark可以正常运行:

N <- 1e6
bench::mark(funcs$loop(N), funcs$vect(N)) # 运行正常

但这种手动方式存在两个明显问题:

  • 新增函数时需手动添加对应调用表达式,容易遗漏;
  • 重复书写函数调用的参数部分,存在冗余。

尝试通过生成表达式列表传入exprs参数时出现报错:

bench::mark(exprs = lapply(funcs, \(f) expression(f(1e6)))) # 报错:Error in f(1e+06) : could not find function "f"

请问如何生成适配bench::mark的exprs参数的表达式列表?


解决方案

要解决这个问题,核心是生成指向列表中具体函数的调用表达式,而非引用循环中的临时变量。以下是几种可行的实现方式:

方法1:使用bquote()生成表达式

bquote()可以保留表达式中的变量引用,通过.指代当前环境中的变量,直接生成目标调用表达式:

N <- 1e6
# 遍历函数列表名称,生成对应调用表达式
expr_list <- lapply(names(funcs), function(name) {
  bquote(funcs[[.(name)]](.(N)))
})
# 给表达式列表命名,方便bench结果识别函数
names(expr_list) <- names(funcs)

bench::mark(exprs = expr_list)

方法2:手动构造调用表达式

使用call()和call2()函数直接构造函数调用结构,明确指定函数位置与参数:

N <- 1e6
expr_list <- lapply(names(funcs), function(name) {
  # 先构造 funcs[[name]] 的表达式,再构造调用该函数的表达式
  call("[[", quote(funcs), name) |>
    call2(N)
})
names(expr_list) <- names(funcs)

bench::mark(exprs = expr_list)

方法3:用purrr::imap()简化代码

如果使用purrr包,imap()可以同时遍历函数列表的元素和名称,代码更简洁:

library(purrr)
N <- 1e6
expr_list <- imap(funcs, ~bquote(funcs[[.(.y)]](.(N))))

bench::mark(exprs = expr_list)

报错原因说明

之前的代码生成的表达式是f(1e6),其中f是lapply循环内的临时变量。当bench::mark执行这些表达式时,会在全局环境中查找f,但全局环境中不存在该函数,因此触发报错。而上述方法均直接生成funcs[["loop"]](1e6)这类具体的调用表达式,避免了引用临时变量的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 05:24:59