I'm trying to write an expression deconstructor or FullForm
-capturer; might even call it a parser, maybe, but that might be too glorious a word.
I got some great ideas from "Head and everything but...", but have plunged headlong back into the fog of my own limited understanding again, which got even foggier when I tried to understand "...function arguments on a stack...". I'd be most grateful for ideas, advice, and more clarity.
Consider this example: a + b + c
. We know its FullForm
is Plus[a, b, c]
, and I can "capture" that FullForm
in a List
with something like
Cases[{a + b + c}, head_[args___] -> {head, args}]
which produces
{{Plus, a, b, c}}
Now I go get myself all drunk on recursion and think I can write
SetAttributes[capture, HoldAllComplete];
capture[expr_?AtomQ] := {Head@expr, expr};
capture[head_[args___]] := {head, capture /@ {args}};
so that something like capture[a + b + c]
gives me fantastic detail
{Plus, {{Symbol, a}, {Symbol, b}, {Symbol, c}}}
or, in stunningly beautiful TraditionalForm
$\left\{\text{Plus},\left( \begin{array}{cc} \text{Symbol} & a \\ \text{Symbol} & b \\ \text{Symbol} & c \\ \end{array} \right)\right\}$
All is well till I try
capture[1 + 2 + 3] ~~> {Integer, 6}
OH NO, it's not Holding inside! What I want, of course, is
$\left\{\text{Plus},\left( \begin{array}{cc} \text{Integer} & 1 \\ \text{Integer} & 2 \\ \text{Integer} & 3 \\ \end{array} \right)\right\}$
My problem is revealed by traceView2
, which I got from "... clearest way to represent ..."
We see that 1 + 2 + 3
arrives held to AtomQ
, as expected, but greedy old evaluator grabs it right there and smooshes it into 6. Everywhere else in the trace, the same thing happens. I don't know an easy way to stop the evaluator inside my capture
faction.
It has occurred to me to copy and adapt the code of traceView2
to my application, since it exploits Trace
to get ahead of the evaluator, and I will proceed that way unless I receive a cool answer here. In my dreams I imagine something like
SetAttributes[capture, DudeReallyHoldAllCompleteEverywhere];
or
SetAttributes[capture, HoldAllComplete, Levels -> Infinity];