调试R中的泛型函数

时间:2009-11-10 13:47:13

标签: debugging r

如何调试泛型函数(在调试包中使用debug或mtrace)?

作为一个例子,我想在NADA包中调试cenreg,特别是采用公式输入的方法。

您可以像这样检索方法详细信息:

library(NADA)
getMethod("cenreg", c("formula", "missing", "missing"))

function (obs, censored, groups, ...) 
{
    .local <- function (obs, censored, groups, dist, conf.int = 0.95, 
        ...) 
    {
        dist = ifelse(missing(dist), "lognormal", dist)

...
}

问题是cenreg本身看起来像这样:

body(cenreg)
# standardGeneric("cenreg")

我不知道如何单步执行底层方法,而不是通用包装器。

2 个答案:

答案 0 :(得分:14)

我的前两个建议非常基本:(1)将函数调用包装在try()中(经常提供有关S4类的更多信息)和(2)在抛出错误后调用traceback() (有时可以提示问题真正发生的地方)。

在此方案中调用debug()无效,因此您需要使用tracebrowser。从调试帮助页面:

"In order to debug S4 methods (see Methods), you need to use trace, typically 
calling browser, e.g., as "
  trace("plot", browser, exit=browser, signature = c("track", "missing")) 

S4课程很难使用;一个例子是the debug package文档中的注释(关于mtrace()与S4类的用法):

"I have no plans to write S4 methods, and hope not to have to
debug other people’s!"

A similar question was asked recently on R-Help。邓肯默多克的建议:

"You can insert a call to browser() if you want to modify the source.  If
you'd rather not do that, you can use trace() to set a breakpoint in it.
The new setBreakpoint() function in R 2.10.0 will also work, if you
install the package from source with the R_KEEP_PKG_SOURCE=yes
environment variable set.  It allows you to set a breakpoint at a
particular line number in the source code."

我之前从未这样做过(它需要R 2.10.0),但您可以尝试使用R_KEEP_PKG_SOURCE=yes从源代码安装。

顺便说一句,您可以使用github中的CRAN mirror of NADA来浏览源代码。

答案 1 :(得分:0)

很长一段时间以来,这一直是S4方法调试的标准麻烦点。正如查尔斯·普莱西(Charles Plessy)所指出的那样,我与迈克尔·劳伦斯(Michael Lawrence)一起为R添加了许多功能,旨在简化此操作。

debugdebugonceundebugisdebugged现在都采用了适合指定s4方法的签名参数。此外,以这种方式调试S4方法会绕过您以前必须手动处理的怪异的实现细节,方法是通过browser trace进入方法,逐步执行.local定义,然后调试,然后继续。

此外,我添加了debugcall,您将对其进行实际,完整的调用。这样做可以设置第一个关闭消息的调试,在评估不是S3或S4标准泛型的调用时将调用该消息。因此,如果您要调用的是非泛型函数,那将只是被调用的顶级函数,但是如果它是标准的S3或S4泛型函数,则将调试的第一个 method 调试为而不是通用。 “标准的S3泛型”定义为一种函数,其中主体中的第一个顶级(忽略花括号)调用是对UseMethod的调用。

请注意,我们在此设计上来回走动,但最终还是以debugcall为依据。不是实际上是在执行正在调试的函数调用,但它会返回调用表达式您可以根据需要将其传递给eval,如?debugcall所示。