[英]Nicer way to build `call` from `list` and get a nice `traceback`
我正在R中从带有命名参数的list
建立对函数(元素(元素的数量和元素的名称)可能会变化)的call
。 使用call
的动机是在发生错误时获得比do.call
更好的traceback()
。 这是一个例子
set.seed(1)
X <- structure(replicate(3, rnorm(200), simplify = FALSE),
names = c("X1", "X2", "X3"))
str(X)
#R List of 3
#R $ X1: num [1:200] -0.626 0.184 -0.836 1.595 0.33 ...
#R $ X2: num [1:200] 0.409 1.689 1.587 -0.331 -2.285 ...
#R $ X3: num [1:200] 1.074 1.896 -0.603 -0.391 -0.416 ...
func <- function(...){
# ... actual code
if(TRUE) # some error
stop("Boh :(")
}
# `do.call` gives an un-nice traceback
do.call(func, X)
#R Error in func(X1 = X$X1, X2 = X$X2, X3 = X$X3) : Boh :(
traceback()
#R 3: stop("Boh :(") at #3
#R 2: (function (...)
#R {
#R if (TRUE)
#R stop("Boh :(")
#R })(X1 = c(-0.626453810742332, 0.183643324222082, -0.835628612410047,
#R 1.59528080213779, 0.329507771815361, -0.820468384118015, 0.487429052428485,
#R 0.738324705129217, 0.575781351653492, -0.305388387156356, 1.51178116845085,
#R 0.389843236411431, -0.621240580541804, -2.2146998871775, 1.12493091814311,
#R -0.0449336090152309, -0.0161902630989461, 0.943836210685299,
#R 0.821221195098089, 0.593901321217509, 0.918977371608218, 0.782136300731067,
#R 0.0745649833651906, -1.98935169586337, 0.61982574789471, -0.0561287395290008,
#R -0.155795506705329, -1.47075238389927, -0.47815005510862, 0.417941560199702,
#R [output abbreviated. There are many more lines]
# we can build a call instead like
cl <- list(quote(func))
na <- names(X)
cl[na] <- lapply(na, function(z) substitute(X$z, list(z = as.symbol(z))))
(cl <- as.call(cl))
#R func(X1 = X$z, X2 = X$z, X3 = X$z)
# now we get a nice traceback
eval(cl)
#R Error in func(X1 = X$X1, X2 = X$X2, X3 = X$X3) : Boh :(
traceback()
#R 4: stop("Boh :(") at #3
#R 3: func(X1 = X$X1, X2 = X$X2, X3 = X$X3)
#R 2: eval(cl)
#R 1: eval(cl)
麻烦的是, do.call
方法可以在一行中完成,而call
版本需要几行。 可以在仍然获得不错的(简短且可读的) traceback()
同时做到这一点吗? 我知道我可以将call
版本包装到一个函数中,所以这不是我想要的解决方案。
我知道您说过您不需要额外的功能,但是可以在调试时保持代码完整并使用trace
使用新功能:
do_call <- function(fun,X){
# remove these comments to use as a simple replacement for do.call
# cl <- list(substitute(fun))
# na <- names(X)
cl[na] <- lapply(na, function(z) substitute(X$z, list(z = as.symbol(z))))
(cl <- as.call(cl))
eval(cl)
}
trace(do.call, quote(return(eval.parent(do_call(substitute(what),substitute(args))))))
do.call(func, X)
#R Error in func(X1 = X$X1, X2 = X$X2, X3 = X$X3) : Boh :(
traceback()
# 12: stop("Boh :(") at #3
# 11: func(X1 = X$X1, X2 = X$X2, X3 = X$X3)
# 10: eval(cl)
# 9: eval(cl) at #6
# 8: do_call(substitute(what), substitute(args))
# 7: eval(expr, p)
# 6: eval.parent(do_call(substitute(what), substitute(args)))
# 5: eval(expr, p)
# 4: eval(expr, p)
# 3: eval.parent(exprObj)
# 2: .doTrace(return(eval.parent(do_call(substitute(what), substitute(args)))),
# "on entry")
# 1: do.call(func, X)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.