Sometimes I'll use Print[1]
or Print[n]
to debug in a long loop, but it's really a boring job to add these sentence by sentence and removing them sentence by sentence. (It's already boring to read this first three lines sentence by sentence so you can imagine how boring it is to add these stuff sentence by sentence. :P) So my question is how to throw this job to a program?
Let's take this small (and stupid) program as an example:
Do[j=i^2;Thread[{{1},{2,3}}],{i,3}]
I would like to add two Print
in this program to determin where the problem occurs.
Do[Print@1;j=i^2;Print@2;Thread[{{1},{2,3}}],{i,3}]
In this way I can know that it's the second step that goes wrong.
Any idea how to do this automatically?
Answer
Yesterday I checked my account's question list again and find this question lying inside. After a year wrestling mostly with Hold
stuffs, I think I finally found a, well, not that elegant solution. Any suggestions or new answers are surely welcomed!!!
It seems that this question is not that bad, actually I may say that It's quite hard for one to solve this problem using all sorts of evaluation manipulation techniques. and it has real applications sometimes.
As usual, my code first:
SetAttributes[adddebug, HoldFirst]
adddebug[orig_, func_: Echo, level_: {2}] :=
Module[{$count = 1, tempf},
Replace[
Replace[Hold[orig], HoldPattern[CompoundExpression[comp__]] :>
Block[{},
tempf @@
Riffle[List @@ (Hold /@ Hold[comp]),
With[{$func = func, q = #}, Hold@$func@q] & /@
Range[$count, ($count = $count + Length@Hold[comp] + 1) -
1], {2, -1, 2}] /; True],level],
tempf[seg__] :>
Block[{},
tempf[Hold[CompoundExpression]] @@ (tempf /@ {seg}) /; True],level] /. tempf[Hold[seg_]] :> seg
]
adddebug[Do[j = i^2; Thread[{{1}, {2, 3}}], {i, 3}]]
The result is satisfying
Hold[Do[j = i^2; Echo[1]; Thread[{{1}, {2, 3}}]; Echo[2], {i, 3}]]
Some additional notes:
Why I say this question is not that trivial is because I should protect CompoundExpression
and its content from evaluating while still need to operate on CompoundExpression
's structure and use in place evaluation techniques extensively.
So I install protection in the following ways:
When pattern-matching, Use
HoldPattern
Use unique symbol
tempf
as a medium to mark WhereCompoundExpression
previoulsly existed. Usetempf[Hold[CompoundExpression]]
.make every element of CompoundExpression Hold at all times, and mark them using
tempf[Hold[expr]]
I'm quite satisfied by the last
ReplaceAll
's design, as previously I’ve already make where should beCompoundExpression
tempf[Hold[CompoundExpression]]
and where should beCompoundExpression
's elementtempf[Hold[element]]
, Now I can safely useReplaceAll
once to make those stuffs back to their original form!
I still am looking foward to a better solution, so if anyone has any idea, post something, Thanks!
Comments
Post a Comment