I'm looking for a function that applies the following behavior to an expression:

-When the expression is given as the full input, or as part of a function that cannot be evaluated, it remains in unevaluated form. -When the expression is used for a function, it is evaluated.

Defer[] won't evaluate it in a function. Unevaluated[] leaves itself in evaluated when used directly as output.

Essentially, I need a function F[] that will output the following:

  • F[1-1/2] outputs 1-1/2, NOT 1/2

  • Times[F[1-1/2],5] outputs 5/2, NOT (1-1/2)5

  • Times[F[1-1/2],x] outputs (1-1/2)x, NOT x/2

If the solution only works for a specific internal expression, that works, because I only need this for one function.

  • 2
    $\begingroup$ have a look at the documentation for UpValues and HoldForm. $\endgroup$
    – Verbeia
    Jan 10 '13 at 5:06
  • $\begingroup$ Is Times your actual "specific internal" function? Your third requirement is likely going to require knowledge of that function and special handing. $\endgroup$
    – Mr.Wizard
    Jan 11 '13 at 5:49

Something along these lines?

SetAttributes[f, HoldAll];
f /: h_?headPredQ[b___, f[arg_], a___] := 
  With[{res = h[b, arg, a]}, res /; Hold[res] =!= Hold[h[b, arg, a]]];
Format[f[arg_]] := Defer[arg];
headPredQ[h_] := MemberQ[Attributes@h, NumericFunction];


New version that contemplates the third case I had forgot (thanks @MichaelE2). This compares the evaluated result of the expression with the result of only applying attribute transformations like those of Flat, Sequence or Orderless. So, reorderings of arguments in a multiplication aren't interpreted as a real evaluation now

SetAttributes[f, HoldFirst];
f /: h_?headPredQ[b___, f[arg_], a___] :=
   s /: h[s, args___] := Hold[h[args]]; 
   With[{res = h[b, arg, a]},
    res /; Hold[res] =!= h[s, b, arg, a]]];
Format[f[arg_]] := Defer[arg];
headPredQ[h_] := MemberQ[Attributes@h, NumericFunction];
  • $\begingroup$ For Times[f[1 - 1/2], x] I'm getting the output x/2 and the OP seems to want (1-1/2)x. Perhaps use something like ?(VectorQ[{#},NumericQ]&) on a and b? $\endgroup$
    – Michael E2
    Jan 10 '13 at 14:32
  • $\begingroup$ @MichaelE2 For BlankNullSequence patterns only the NumericQ condition needs to be specified. $\endgroup$
    – VF1
    Jan 11 '13 at 2:55

I like how Rojo's answer tests for evaluation in general, but it requires an additional fix as noted by Michael E2. So here is another approach where I interpret "evaluating" in the question as meaning "to yield a numerical result". This can be tested with NumericQ. Then I just have to take care of the non-numeric case by returning the Defered result and also stopping the potential recursion that will happen if f[x] is not inside another function:

SetAttributes[f, HoldFirst];
f /: h_[a___, f[x_], b___] := 
  If[TrueQ@NumericQ[h[a, x, b]], h[a, x, b],
   Defer[h[a, x, b]] /. HoldPattern[If[False, y_, ___]] :> y];

The replacement rule with HoldPattern looks for the pattern that will arise when the first If statement is itself the Head wrapping f, as will happen when f wasn't wrapped by anything else. That's when a recursion would occur, so the argument has to be pulled out through the variable y.

Now I get for example:

f[1 - 1/2] 5

(* ==> 5/2 *)

f[1 - 1/2] x

(* ==> x (1 - 1/2) *)

f[1 - 1/9]

(* ==> 1 - 1/9 *)

This is how I understood the question - I'm not entirely sure if Defer was desired or not. Maybe you want to replace Defer by HoldForm, but the rest wouldn't change.

  • $\begingroup$ Defer was the desired function, but note that the input may not necessarily be numeric. For example, F["a"<>"b"] should output "a"<>"b" while F["a"<>"b"]<>"c" outputs "abc" ... $\endgroup$ Jan 11 '13 at 2:28
  • $\begingroup$ I don't think that was clear from the question, and the last result you stated is not the Defer result, so I'm still unsure what you want. $\endgroup$
    – Jens
    Jan 11 '13 at 3:24

Revisiting this question after noticing the third requirement of the question and the statement that you need this only for one function I believe you may want this:

SetAttributes[f, HoldFirst]

Format[f[x_]] := Defer[x]

f /: Times[f[x_], y_?NumericQ, z___] := (x*y) z


f[1 - 1/2]

Times[f[1 - 1/2], 5]

Times[f[1 - 1/2], x]
1 - 1/2


x (1 - 1/2)

Original answer

It seems to me that (at least on version 7) Unevaluated behaves as you desire F to.
If you do not have a $Post or $PrePrint function defined a raw Unevaluated[2+2] should not evaluate:

In[1]:= Unevaluated[2 + 2]

Out[1]= Unevaluated[2 + 2]

All that remains is to Format the output to hide Unevaluated itself:


Format[Verbatim[Unevaluated][expr_]] := Defer[expr]
In[3]:= Unevaluated[2 + 2]

Out[3]= 2 + 2

Of course since you said:

If the solution only works for a specific internal expression, that works, because I only need this for one function.

Verbeia's alluded solution is sufficient:

SetAttributes[f, HoldAll]

Format[f[expr_]] := Defer[expr]

StringJoin[a___, f[inside_], b___] ^:= StringJoin[a, inside, b]


f["a" <> "b"]
"a" <> "b"
f["a" <> "b"] <> "c"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.