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
) という名前が付けられ、各行エントリには各引数と関数出力のサブエントリがあります。引数エントリは、最初に、実際の引数が一致する形式の名前で構成され、2 番目に、その引数に指定された式または名前 (引数が単なる定数の場合はプレースホルダー) で構成されます。そして 3 番目に、その式の値は、関数への入力時にすぐに強制されたかのようになります。(プロミスが最初に守られた時点での値を取得したいのですが、それははるかに難しい問題のように思えます。2 つの値はほとんどの場合同じです)。
(存在する場合)に割り当てられたすべての引数...
は、dots = list() サブリストに入れられ、エントリに名前がある場合は名前..1, ..2,
が付けられ、位置的に割り当てられている場合は適切にラベル付けされます (など)。各行のサブリストの最後の要素は、出力の名前とその値になります。
これのポイントは、コード ブロックの操作のかなり完全な記録を作成することです。これは、反復に限定されず、各ステップのより詳細な記録を保持する精巧なバージョンに類似していると思います。purrr::safely
実際、関数がエラーで終了した場合、リストエントリと同様にエラーメッセージが必要になります.エラーが生成される前に持っていた可能性のある一致した引数の多く。
これは、このような線形コードのデバッグに非常に役立つように思えます。これにより、RStudio デバッガーだけでは難しいことが可能になります。たとえば、コードを逆方向にトレースできます。out2 の値が正しくないことは、後で出力を確認するまでわからない場合があります。シングルステップでは、大量の追加コードを挿入しない限り、中間値は保持されません。さらに、これにより、Promise が作成される前に発生する一致エラーを追跡するために必要な情報が保持されます。このようなエラーの結果としてシングル ステップで出力が表示されるまでには、一致する情報は蒸発している可能性があります。
私は実際に、パイプされた関数を受け取り、パイプを削除してこの形式にするコードを、テキスト操作だけで作成しました。(確かに、これを考えさせられたのはジョン・マウントの「ビザロ・パイプ」でした)。そして、私、または私たち、またはあなたがこれを行う方法を理解できれば、各関数が次の関数を呼び出し、外部ではなく内部で引数を提供する2番目のバージョンで真剣に実行したいと考えています-トレースバックのようにここで、渡された引数の値と、関数名およびフォーマルを取得します。他の言語にはそのようなデバッグ環境 (GDB など) があり、R 用のデバッグ環境を少なくとも 5 年、おそらく 10 年は望んでいましたが、これはそれに向けた一歩のようです。