我试图弄清楚是否有可能通过大量的编程,通过使用 R 的元编程功能来创建某种调试功能。
假设我有一段代码,这样每一行都使用之前一行的输出作为其全部或部分输入——你可以用管道构建的那种代码(尽管这里没有使用管道)。
{
f1(args1) -> out1
f2(out1, args2) -> out2
f3(out2, args3) -> out3
...
fn(out<n-1>, args<n>) -> out<n>
}
例如,它可能是:
f1 <- function(first_arg, second_arg, ...){my_body_code}
,
你f1
在块中调用:
f1(second_arg = 1:5, list(a1 ="A", a2 =1), abc = letters[1:3], fav = foo_foo)
其中foo_foo
是在 的调用环境中定义的对象f1
。
我想要一个可以环绕我的块的函数,它可以为每一行代码在列表中创建一个条目。每个条目都将被命名为 ( line1, line2
),并且每个行条目都有一个用于每个参数和函数输出的子条目。参数条目将首先包含与实际参数匹配的形式的名称,其次,如果有一个,则提供给该参数的表达式或名称(如果参数只是一个常量,则为占位符),第三,该表达式的值,就好像它在进入函数时立即被强制一样。(我宁愿在第一次遵守诺言时就获得价值,但在我看来,这似乎是一个更难的问题,而且这两个值通常是相同的)。
分配给...
(如果有的话)的所有参数都将放在一个dots = list() 子列表中,如果条目有名称,则命名为条目,..1, ..2,
如果它们按位置分配,则带有适当的标签(等)。每行子列表的最后一个元素是输出名称及其值。
这样做的目的是创建一个相当完整的代码块操作记录。我认为这类似于它的详细版本,purrr::safely
它不限于迭代并保留每个步骤的更详细记录,实际上,如果函数因错误退出,您会希望列表条目中的错误消息以及在产生错误之前可能有很多匹配的参数。
在我看来,这对于调试这样的线性代码非常有用。这使您可以仅使用 RStudio 调试器完成一些困难的事情。例如,它可以让您向后跟踪代码。在我看到后来的输出之前,我可能不知道 out2 中的值不正确。除非您插入一堆额外的代码,否则单步执行不会保留中间值。此外,这还保留了您在创建 Promise 之前跟踪发生的匹配错误所需的信息。当您通过单步操作看到此类错误导致的输出时,匹配信息可能已经消失了。
实际上,我已经编写了采用管道函数并消除管道以将其置于这种格式的代码,仅使用文本操作。(事实上,正是约翰·芒特的“Bizarro pipe”让我想到了这一点)。如果我,或者我们,或者你,可以弄清楚如何做到这一点,我希望在第二个版本上认真运行,每个函数调用下一个函数,在内部而不是外部为其提供参数——比如回溯您可以在其中获得传递的参数值以及函数名称和形式。其他语言也有类似的调试环境(例如 GDB),我一直希望 R 有一个至少五年,也许是 10 年,这似乎是朝着它迈出的一步。