# With/Function(/etc) replacement behaviour

Can anyone explain to me this behaviour? I've been having more than a couple of similar doubts these last weeks.

For example

f[_?NumericQ] := 8;


Now, if I do

With[{a = f[a]}, HoldForm@Block[{NumericQ = True &}, a]]


I get

Block[{NumericQ = True &}, f[a]]


And if I do

Block[{NumericQ = True &}, f[a]]


I get

8


So far so good... Another so-far-so-goodie is (notice the :=)

With[{a := f[a]}, Block[{NumericQ = True &}, a]]

8


Question: Can anyone help me understand why this output?

With[{a = f[a]}, Block[{NumericQ = True &}, a]]

f[a]


Could it be that With (= version) not only evaluates and replaces, but also guarantees that the replaced expression won't be reevaluated no matter what until the With is exited? If that's the case I wasn't expecting that. What's happening here?

EDIT

Question also applies to Function

Block[{NumericQ = True &}, #] &[f[a]]

f[a]


And not just those too. Everything I try behaves the same way... A couple of other examples

Block @@ (Hold[{NumericQ = True &}, exp] /. exp -> f[a])

With[{a := Evaluate@f[a]}, Block[{NumericQ = True &}, a]]


both give f[a]

EDIT

With[{g = h}, h = 8; Print[g] ]


prints 8, not h, so clearly h is reevaluated inside the With in this case, so g is not so constant.

EDIT

Ok, another couple of examples

In[10]:= ClearAll[h, f];
h := 8 /; NumericQ["a"];
f[_?NumericQ] := 8;


Now, both h and f[a] remain unevaluated

In[21]:= {h, f[a]}

Out[21]= {h, f[a]}


Now, with the OwnValues everything works as expected

In[17]:= With[{g = h},
Block[{NumericQ = True &}, g]]

Out[17]= 8


But with the DownValues, it doesn't

In[19]:= With[{g = f[a]},
Block[{NumericQ = True &}, g]]

Out[19]= f[a]


Similarly

f[a_?NumericQ] := 8;
g[e_] := Block[{NumericQ = True &}, e]


f[a] evaluates to f[a], but weirdly

In[17]:= g[Unevaluated@f[a]]

Out[17]= 8

In[18]:= g[f[a]]

Out[18]= f[a]

-

f[_?NumericQ] := 8

With[{a = f[a]}, Block[{NumericQ = True &}, a]]


outputs f[a].

This is because of caching of the result of Conditions and PatternTests. Compare with this:

With[{a = f[a]}, Block[{NumericQ = True &}, Update[]; a]]

(* ==> 8 *)


Generally, making global changes that might affect the outcome of a Condition will have unpredictable results due to caching---unless you use Update[] after each change.

-
Szabolcs to the rescue...... – Rojo Feb 15 '12 at 8:30
Interesting, the relation of this behavior to caching wasn't obvious to me. +1. – Leonid Shifrin Feb 15 '12 at 13:13
@Leonid and Rojo: the clue was that TracePrint didn't show NumericQ being evaluated for the second time. – Szabolcs Feb 15 '12 at 13:15
@Szabolcs Yes, I also used Trace and saw that there was no second evaluation. I just read your answer first, and realized that without Trace, this wouldn't be something I'd guess right away. – Leonid Shifrin Feb 15 '12 at 13:17

See the answers to this question.

The short answer is that, yes, With is designed for creating local constants, so once the local expressions are initialised, they won't be re-evaluated.

Using the {a := f[a]} notation gets around this design feature of With. To be honest, though, I have never seen it used before. It is not mentioned in the documentation, and I can't help thinking that it breaks something in subtle ways.

Of course Block[{a = f[a], NumericQ = True &}, a] gives a $RecursionLimit error, but returns 8. Is there a reason why Block[{NumericQ = True &}, f[a]] doesn't fulfil your purpose? In response to your edit, Block[{NumericQ = True &}, #] & [f[a]] doesn't give your desired output because the f[a] is outside the Block scoping construct. Again, see Leonid's answer to the previously mentioned question as well as the other answers there. - I wanted f[a] evaluated with normal definitions (NumericQ meaning what it means) and afterwards (if necessary) reevaluated letting it match the ?NumericQ definition. I thought I would get that behaviour with the With or with a Function but I was clearly wrong – Rojo Feb 15 '12 at 5:44 With may be designed to define constants that cannot be changed, but I definately expected Function to simply replace it's arguments and evaluate. Shouldn't f[a] be put inside the Block before the Block is even considered? – Rojo Feb 15 '12 at 5:53 I think I've seen SetDelayed used in With discussed on SO. Maybe by Simon or Leonid. – Mike Honeychurch Feb 15 '12 at 6:15 @Mike I learned this syntax from Szabolcs, relatively recently. – Leonid Shifrin Feb 15 '12 at 13:10 You can use TracePrint to try to understand how evolves the evaluation step by step: In[23]:= TracePrint[With[{b=f[a]},Block[{NumericQ=True&},b]]] During evaluation of In[23]:= With[{b=f[a]},Block[{NumericQ=True&},b]] During evaluation of In[23]:= With During evaluation of In[23]:= f[a] During evaluation of In[23]:= f During evaluation of In[23]:= a During evaluation of In[23]:= NumericQ[a] During evaluation of In[23]:= NumericQ During evaluation of In[23]:= a During evaluation of In[23]:= False During evaluation of In[23]:= Block[{NumericQ=True&},f[a]] During evaluation of In[23]:= Block During evaluation of In[23]:= True& During evaluation of In[23]:= Function During evaluation of In[23]:= NumericQ=Unevaluated[True&] During evaluation of In[23]:= Set During evaluation of In[23]:= NumericQ=True& During evaluation of In[23]:= True& During evaluation of In[23]:= f[a] During evaluation of In[23]:= f[a] Out[23]= f[a]  As Verbeia said before, you can see that NumericQ[a] is evaluated before it goes to the Block. In the other hand, if you use the delayed set: In[24]:= TracePrint[With[{b:=f[a]},Block[{NumericQ=True&},b]]] During evaluation of In[24]:= With[{b:=f[a]},Block[{NumericQ=True&},b]] During evaluation of In[24]:= With During evaluation of In[24]:= Block[{NumericQ=True&},f[a]] During evaluation of In[24]:= Block During evaluation of In[24]:= True& During evaluation of In[24]:= Function During evaluation of In[24]:= NumericQ=Unevaluated[True&] During evaluation of In[24]:= Set During evaluation of In[24]:= NumericQ=True& During evaluation of In[24]:= True& During evaluation of In[24]:= f[a] During evaluation of In[24]:= f During evaluation of In[24]:= a During evaluation of In[24]:= NumericQ[a] During evaluation of In[24]:= NumericQ During evaluation of In[24]:= True& During evaluation of In[24]:= a During evaluation of In[24]:= (True&)[a] During evaluation of In[24]:= True During evaluation of In[24]:= 8 During evaluation of In[24]:= 8 Out[24]= 8  Evaluation of f[a] happens inside the Block. I changed the With variable to b, so you can see the difference, but the output is the same using a as variable, I don't get any $RecursionLimit error (using Mathematica 8).

-
I know it evaluates before the Block but how can I make it evaluate again inside the Block? – Rojo Feb 15 '12 at 6:02
Well, it seems the right answer is with the delayed set, or with Hold, something like: With[{b = Hold[f[a]]}, Block[{NumericQ = True &}, ReleaseHold[b]]] – FJRA Feb 15 '12 at 6:08
my bad, I wasn't clear. I want it to be evaluated both outside the block with NumericQ meaning it's regular meaning, and then again inside the Block with the redefined NumericQ. Your code works but it only evaluates f[a] inside the Block – Rojo Feb 15 '12 at 6:10