I want to write a custom sow/reap
pair to wrap any piece of code in sow[code]
and call reap
to collect the timing of code
with a tag that is the completely unevaluated version of code
. My proble is that I cannot effectively withhold argument value substitution. I expect to use this pair only on my own functions fun
so I can freely get and set DownValues
as I like. Of course I expect to put many sow
in my definition of fun
. See example:
ClearAll[sow, reap, fun];
Attributes[reap] = {HoldAllComplete};
reap[x_] := Module[{h = (Hold@x)[[1, 0]], old, new, res},
old = DownValues[Evaluate@h]; (* store old DownValues *)
new = old /. {sow[y_] :>
Block[{time, out}, {time, out} = AbsoluteTiming@y;
Sow[ToString@Unevaluated@y -> time]; out]};
DownValues[Evaluate@h] = new;(* install new DownValues *)
res = Reap@x;
DownValues[Evaluate@h] = old;(* restore old DownValues *)
res];
fun[i_Integer] := sow@(Print["CALLED"]; Table[None, {i}]);
Now call reap
on fun
:
In[1]:= reap[fun[2]]
During evaluation of In[1]:= CALLED
Out[1]= {{None, None}, {{"Print[CALLED]; Table[None, {2}]" -> 0.0000418147}}}
This is almost what I want, but not exactly. How can I keep i
from evaluating to the argument value 2
? That is, I want to have "Print[CALLED]; Table[None, {i}]"
instead of "Print[CALLED]; Table[None, {2}]"
in the resulting tag. I guess this cannot be solved locally within any definition of sow
, hence the DownValue
-manipulation within reap
. Can it be solved with the injector pattern or the Trott-Strzebonski in-place evaluation?
I know that I can specify tags manually in Sow
but I specifically want to avoid this and simply use sow
as a one-argument function.