Temporary message: I am now really confused. I am not sure how using Power and Unevaluated together works in the examples below.
While answering this question, I stumbled upon the following.
We have
Power[Unevaluated[
Power[Power[Power[Power[Power[Times[1, a1], a2], a3], a4], a5],
a6]], a7]
-> Power[Power[Power[Power[Power[Power[a1,a2],a3],a4],a5],a6],a7]
Where there seems to be some rule involving deeply nested patterns at work (correct me if I'm wrong). Compare this with
Power[Unevaluated[
Power[Power[Power[Power[Power[Times[2, a1], a2], a3], a4], a5],
a6]], a7]
-> Power[Unevaluated[Power[Power[Power[Power[Power[Times[2,a1],a2],a3],a4],a5],a6]],a7]
Where nothing happens. Note also that
a2 = 3;
Power[Unevaluated[Power[Times[2, a1], a2]], a3]
-> Power[Unevaluated[Power[Times[2, a1], a2]], a3]
But that
Clear[a1, a2];
a1 = 3;
Power[Unevaluated[Power[Times[2, a1], a2]], a3]
-> Power[Power[6,a2],a3]
Most importantly, note that
Clear[a1, a2, a3, f];
f[1] = 2;
Power[Unevaluated[Power[f[1], a2]], a3]
-> Power[Power[2,a2],a3]
Whereas
Clear[a1, a2, a3, f];
f[] = 2;
Power[Unevaluated[Power[f[], a2]], a3] // FullForm
-> Power[Unevaluated[Power[f[],a2]],a3]
We have
FullForm /@
Trace[Power[Unevaluated[Power[Power[Times[1, b], c], d]], e],
TraceOriginal -> True] // Column
->
(*output*)
HoldForm[Power[Unevaluated[Power[Power[Times[1,b],c],d]],e]]
List[HoldForm[Power]]
List[HoldForm[e]]
HoldForm[Power[Power[Power[Times[1,b],c],d],e]]
HoldForm[Power[Power[Power[b,c],d],e]]
List[HoldForm[Power]]
List[HoldForm[Power[Power[b,c],d]]]
List[HoldForm[e]]
HoldForm[Power[Power[Power[b,c],d],e]]
I am not sure if what to conclude from this.
Note that
Power[Hold[Times[1, 2]], 2] // FullForm
-> Power[Hold[Times[1,2]],2]
so that Times is of course not cleared if there is a function with attribute HoldAll surrounding it. Note that the test functions below also depend on this.
Not so important: Tools
The following are tools to play with larger expressions like this
(*warning! might clear unexpected variables!*)
Clear @@ Names["arg*" | "a" | "b"]
SetAttributes[holderToken, HoldAll];
tester = And[First[#] == {}, Length[#[[2]]] == kkkk + 1,
Last[#] == {}] &;
headFinder =
Function[
ReplaceAll[
Unevaluated@Unevaluated@
Cases[
#,
head, Infinity, Heads -> True
]
,
{{head -> Unevaluated}, {head -> Power}, {head -> Times}}
]
];
expression :=
With[{compoWithHeldArg =
Unevaluated @@
(
DeleteCases[
Hold@
Evaluate[(Composition @@
Array[With[{argu = Symbol["arg" <> ToString[#]]},
Function @@ {argu, Power[argu, a[#]]}] &, kkkk])[
holderToken[Times[1, b]]]]
,
holderToken, Infinity, Heads -> True
]
)
}
,
Power[compoWithHeldArg, a[0]]
];
We then have
kkkk = 12;
tester@headFinder@expression
-> True
and
kkkk=12;
expression // FullForm
-> Power[Power[Power[Power[Power[Power[Power[Power[Power[Power[Power[Power[Power[b,a[12]],a[11]],a[10]],a[9]],a[8]],a[7]],a[6]],a[5]],a[4]],a[3]],a[2]],a[1]],a[0]]
and we see that
Unevaluated @@
(
DeleteCases[
Hold@
Evaluate[(Composition @@
Array[With[{argu = Symbol["arg" <> ToString[#]]},
Function @@ {argu, Power[argu, a[#]]}] &, kkkk])[
holderToken[Times[1, b]]]]
,
holderToken, Infinity, Heads -> True
]
)//FullForm
-> Unevaluated[Power[Power[Power[Power[Power[Power[Power[Power[Power[Power[Power[Power[Times[1,b],a[12]],a[11]],a[10]],a[9]],a[8]],a[7]],a[6]],a[5]],a[4]],a[3]],a[2]],a[1]]]
Where the Times is still present. So indeed applying Power[#,2]& to the expression above clears the Times.
Deep pattern
If we don't want to make any replacements, but just a deep pattern, we can recursively define a pattern as follows
Clear[patt];
patt = (_?AtomQ) | f[x_ /; MatchQ[x, patt]];
We then have
MatchQ[f[f[1]], patt]
(-> True)
A function that acts a bit like Power
Maybe something similar is going on with Power. That is, there is some pattern that searches in a deep way (maybe some kind of expressions that it can simplify), but the rule applied is trivial. I am confused and I thought the Times that was found was actually replaced by the same rule that (/whose pattern) found it. Now I am not sure if we should even speak of a rule in this case.
I can make a function that works (at least a bit) like Power in very limited cases.
ClearAll[shortCondition]
SetAttributes[shortCondition, HoldAll]
shortCondition[x_] :=
MatchQ[Unevaluated[x],
HoldPattern[
Times[___, 1, ___] | power[xxxx_ /; shortCondition[xxxx], _]]]
ClearAll[power]
power[x_ /; shortCondition[x], n_] := power[x, n]
We then have
power[Unevaluated[power[Times[1, 2], e]], d]
-> power[power[2, e], d]
-> power[2, 2]
Whereas
power[Unevaluated[power[Times[2, 2], e]], d]
-> power[Unevaluated[power[Times[2, 2], e]], d]
However, I think we should conclude from the Trace further above that Power works a little differently.
The new question is: How can we simulate the behavior of Power, especially the aspect of it that seems to apply rules deeply in the expression that is one of its arguments.
.
.
.
.
.
Old text, which seems to distract now
The more complicated problem of also making a non trivial replacement seems very difficult, but I'd still like to know if somebody knows if there is a way.
If we also want to make a replacement , that makes things difficult. In the example in which f has a recursive pattern, we might want to replace the atom found by 0. In the example of power we might want to replace Times[a___,1,b___] by Times[a,b]. I think it is pretty unlikely that there is an elegant way of doing things. I had some hope that there would be a way make replacements in a general way, as I believed Power might work in this way. Now I don't think Power works in this way, but I still curious.
As a small remark, not that we of course have
MatchQ[f[f[1]], (___f)[1]]
-> False
and
MatchQ[Unevaluated[Sequence[f, f, f][1]], ___[1]]
Repeated and PatternSequence also seemed like they were maybe the way to go. But maybe not.
The question was: Is it possible to define a rule in such a way that it determines whether an expression is of the form
f[___, f[___, ...[f[___, x_head ,___]] ,___], ___]
where the ...[] means that f is applied an arbitrary number of times in this way, and "do something with x on the RHS"?
To clarify, we might want to define something like
f[___, f[___, ...[f[___, x_Integer ,___]] ,___], ___]:= x
Or in case of power
power[power[z...[Times[1,x_]],y_],z1_]:=power[power[z[x],y],z1]
where I have given the pattern of "repetitively applying power" the name z.
A way of writing this in that might be parseable by Mathematica could be
z...power[Times[1,x_],y_]:=z[x,y]
Possibly the answer is: maybe in version 13. But any feedback is welcome :)
Unevaluated
, and useHold
and friends instead. Another one: things likeCases[Unevaluated[expr],s:(your-pattern):>Hold[s],Infinity]
should provide sufficient tools to destructure and analyze any expression safely, with no evaluation leaks. $\endgroup$With[{something=Unevaluated@@{expr}},_]
. I will now look at that discussion. $\endgroup$