Working my way through Robby Villegas's lovely notes on withholding evaluation, I almost got Polish Notation on my first try. Here is my final solution, which seems to work well enough:
ClearAll[lispify];
SetAttributes[lispify, HoldAll];
lispify[h_[args___]] :=
Prepend[
lispify /@ Unevaluated @ {args},
lispify[h]];
lispify[s_ /; AtomQ[s]] := s;
lispify[Unevaluated[2^4 * 3^2]]
produces
{Times, {Power, 2, 4}, {Power, 3, 2}}
My first try had only one difference, namely
lispify /@ Unevaluated /@ {args}
and sent me down a frustrating rabbit hole until I stumbled on the corrected one above.
Would someone be so kind as to explain the details of both the correct and incorrect solution?
EDIT:
As a minor bonus, this enables a nice way to visualize unevaluated expression trees:
ClearAll[stringulateLisp];
stringulateLisp[l_List] := stringulateLisp /@ l;
stringulateLisp[e_] := ToString[e];
ClearAll[stringTree];
stringTree[l_List] := First[l][Sequence @@ stringTree /@ Rest[l]];
stringTree[e_] := e;
ClearAll[treeForm];
treeForm = TreeForm@*stringTree@*stringulateLisp@*lispify;
treeForm[Unevaluated[2^4 + 3^2]]
Answer
You must remember that Unevaluated
only "works" when it is the explicit head of an expression. In the non-working format the structure looks like:
TreeForm @ HoldForm[lispify /@ Unevaluated /@ {arg1, arg2}]
Note that Unevaluated
does not surround arg1
and arg2
therefore they evaluate prematurely.
Now compare the working structure:
TreeForm @ HoldForm[lispify /@ Unevaluated @ {arg1, arg2}]
Here Unevaluated
does surround arg1
and arg2
and evaluation is prevented.
See also:
By the way you can show an unevaluated TreeForm
by using an additional Unevaluated
to compensate for an apparent evaluation leak.
treeForm =
Function[expr, TreeForm @ Unevaluated @ Unevaluated @ expr, HoldFirst]
Test:
2^4*3^2 // treeForm
Also possibly of interest: Converting expressions to "edges" for use in TreePlot, Graph
Comments
Post a Comment