I got this error when using Mathematica:
Part::partw: "Part 5 of {{0.637537,0.362463},{0.00038282,0.999617},
{0.0928437,0.907156},{0.0000222833,0.999978}} does not exist."
I know why it is generated, but the problem is my code is so lengthy and I cannot find where it comes from. Is there any syntax in Mathematica by which I can resolve my problem? Thanks.
Answer
Implementation
Here is a better version of my debug function posted here, which would print the stack on the first message generated, and abort the computation. I have used it extensively with great effect in many cases.
This constructs the nested OpenerView
from an arbitrary expression:
ClearAll[openerDress];
SetAttributes[openerDress, HoldAll];
openerDress[f_[args___]]:=
OpenerView[{
HoldForm[f],
HoldForm[f]@@Map[openerDress,Unevaluated[{args}]]
}];
openerDress[x_]:=HoldForm[x];
This uses openerDress
to represent stack of execution in a way that is expandable when clicked:
ClearAll[stackPrettify];
stackPrettify[stack : {__HoldForm}] :=
Column @ {
Replace[stack, HoldForm[f_[x___]] :> openerDress[f[x]], 1],
Style[Map[Short, Last[stack], {2}], Red]
};
stackPrettify[___] := Null;
This is a generator of dynamic environments with redefined functions, encapsulating the Villegas - Gayley technique:
ClearAll[withRedefined];
withRedefined[f_Symbol, extraCondition_, beforeF_, afterF_]:=
Function[
code
,
Internal`InheritedBlock[{f},
Module[{inF, dv = DownValues[f]},
Unprotect[f];
DownValues[f]={};
(call:f[args___]) /; extraCondition[args] && !TrueQ[inF]:=
Block[{inF = True},
beforeF[args];
call;
afterF[args]
];
DownValues[f] = Join[DownValues[f],dv];
Protect[f];
];
code
]
,
HoldAll
];
A couple more of the helper functions:
ClearAll[printStack];
printStack[start_, end_]:=Print[stackPrettify[Take[Stack[_], {start, end}]]];
ClearAll[heldF];
SetAttributes[heldF, HoldAll];
heldF[body_]:=Function[Null, body, HoldAll];
Finally, this is the actual debugging utility (some formatting imperfections are due to the SE markdown bug regarding the display of symbols containing $
):
ClearAll[debug];
debug[debugSymbol_Symbol:Message, failConditionFunction_:heldF[True]]:=
Function[
code
,
Module[{tag},
withRedefined[
debugSymbol,
heldF[!MatchQ[First[Hold[##]],_$Off]],
heldF[If[failConditionFunction[##],printStack[6, -9]]],
heldF[If[failConditionFunction[##], Throw[$Failed,tag]]]
][Catch[StackComplete[code],tag]]
]
,
HoldAll
];
Tests
There are several ways one can use debug
. The default one is that it breaks on first Message
generated, and prints for you the stack. For example, one may try something like
debug[] @ Sin[Range[10][[1 ;; 15]]]
If you have an access to the source code which you want to debug, and can modify it, you could also use it in the following way:
ClearAll[$debugWrapper]
$debugWrapper[arg_] := arg;
and
debug[$debugWrapper][
Sin[Part[Range[10], $debugWrapper[ 1 ;; 15]]]
]
In other words, you can wrap a piece of code where you suspect a problem, in some wrapper like $debugWrapper
, and then extract the execution stack. You can also set a condition on the first event you want to trigger. For example, the following will only trigger the second event wrapped in $debugWrapper
:
debug[
$debugWrapper,
Function[arg, MatchQ[Unevaluated[arg], _Span], HoldAll]
][
Sin[$debugWrapper@Part[Range[10], 1 ;; 15]];
Sin[Part[Range[10], $debugWrapper[ 1 ;; 15]]]
]
in which case, only the second event wrapped in $debugWrapper
, will be triggered.
Comments
Post a Comment