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.
BlockwithModulein thenewdefinition. Otherwise, unexpected results could occur should any expression in the evaluation chain foryhappen to use the symbolstimeorout. – WReach Oct 18 '19 at 15:01