簡體   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