For anyone coming across this, an answer in the above comments (from J. M.'s ennui) worked for me with minor modifications. All credit goes to him; I'd have never guessed that you'd need two "helpings" of Unevaluated[...]
to achieve the effect of returning an unevaluated expression from a function! Maybe it has to do with the function call itself using Compose, causing one "round" of Unevaluated
to be "used up"??? Speculating here...
EDIT: UnevaluatedDouble[2]
actually did not work for me; trying to use the result downstream results in Unevaluated
persisting forever. See links below.
UnevaluatedSingle[x_] := Unevaluated[x + 1]
UnevaluatedDouble[x_] := Unevaluated@Unevaluated[x + 1]
UnevaluatedSingle[2]
UnevaluatedDouble[2]
Results:
3
Unevaluated[2 + 1]
However, per a post I'll link to in a second, apparently "Unevaluated
is not meant to be a function or stable data type." So although I've found some cases where the above trick was useful for me (at least prima facie), I'm not certain whether its use in this manner is ever "supported" or not.
As to the OP's original question... per this post:
Unexpected behavior of Unevaluated
I'll quote a small excerpt from Mr. Wizard, who in turn quotes a presentation by Robby Villegas:
Unevaluated must be wrapper before argument evaluation, not after, else it isn't stripped.
...
Unevaluated is not meant to be a function or stable data type. It is to be used as a wrapper on an argument in stage 1, before argument evaluation.
Therefore, unless I'm missing something, the OP's question can't be solved quite as suggested, directly, e.g. via:
tee[x_] := (Echo@HoldForm@x; Unevaluated@Unevaluated@x)
... because you can't actually return an expression whose head is Unevaluated
-- it's never meant to be the head of an expression. Instead, one solution would be to make a form of tee
where the call-site passes-in the function to be called and/or the "auxiliary" function (e.g. Echo
) to tee
.
Version 1:
ClearAll[tee]
SetAttributes[tee, HoldAll]
tee[expr_, mainFunc_, auxFunc_ : Echo@*HoldForm] := (auxFunc@Unevaluated@expr; mainFunc@Unevaluated@expr)
tee[Print@3, Apply[foo]]
The following two versions were written to illustrate the syntax difference required when using composition (which was called-out by the OP):
Version 2a
ClearAll[tee]
SetAttributes[tee, HoldAll]
tee[expr_, mainFunc_,
auxFunc_ : Function[e, Echo@HoldForm@e, HoldAll]]
:= (auxFunc@expr; mainFunc@expr)
tee[Print@3, Function[e, foo @@ Unevaluated@e, HoldAll]]
Version 2b
ClearAll[tee]
SetAttributes[tee, HoldAll]
tee[expr_, mainFunc_, auxFunc_ :
Function[e, Echo@*HoldForm@Unevaluated@e, HoldAll]]
:= (auxFunc@expr; mainFunc@expr)
tee[Print@3, Function[e, foo @@ Unevaluated@e, HoldAll]]
Depending on what the "real" application of this was, and your taste in syntax, the below is a final alternative:
ClearAll[tee]
SetAttributes[tee, HoldAll]
tee[expr_, auxFunc_ : Echo@*HoldForm]
:= (auxFunc@Unevaluated@expr; #[Unevaluated@expr] &)
tee[Print@3][Apply[foo]]
Unevaluated
(which prevents works together withComposition
, e.g.(a@*Hold)[Unevaluated@Print@1]
). I will try to make the question a bit clearer in that regard. $\endgroup$Unevaluated
toInactivate
? $\endgroup$SetAttributes[tee, HoldAllComplete]; tee[x_] := (Echo @ HoldForm @ x; Unevaluated[Unevaluated][Unevaluated[x]])
$\endgroup$Unevaluated
is not meant for what you are using it. I would also suggest to useInactive
in combination withActivate
. $\endgroup$