繁体   English   中英

从list生成call并获得不错的traceback的更好方法

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM