1
$\begingroup$

Consider the following (simplified for the purpose of example) definitions:

f[x_] := y /. y -> x
g[x_] := x

Where for example, the definition of f could be motivated e.g. by first getting some expression (y) from a previous calculation, and then deciding to make it into a function.

The problems begin when f is then passed on to a third function, that evaluates it many times (e.g. NIntegrate, Plot, etc), or maybe I then attempt to Compile it. Due to the replacement rule that is saved as part of the definition, everything will be much slower, as can be seen in the following trace:

In[23]:= Trace[f[1]]
Out[23]= {f[1],y/. y->1,{y->1,y->1},y/. y->1,1}

vs

Trace[g[1]]
{g[1],1}

I suspect though I am not certain and haven't profiled this, that the first operation would be significantly slower even when compared to evaluating a more complex mathematical expression, provided it consists of built in functions. I'm open to this being refuted, but my interest is only partly driven by efficiency, so I won't accept an answer that simply refutes my assumption without answering the actual question (I would still find it useful, however).

Now, a plausible way to avoid the previous conundrum is to wrap the RHS of SetDelayed by Evaluate This has its own problems however, namely evaluating unintended parts:

In[16]:= z=1
Out[16]= 1
...
In[42]:= k[x_]:=Evaluate[z+y/.y->x]
In[35]:= Trace[k[1]]
Out[35]= {k[1],1}
In[44]:= Definition[k]
Out[44]= k[x_]:=1+x

What are other methods making the ReplaceAll evaluate once, and what (possibly unintended) consequences do they have? I am mainly interested in something lightweight, that I might actually use in notebooks without my init.m file - not in defining a largs expression to manipulate the SetDelayed lines (though that would still be interesting from an intellectual point of view).

Ideally, this would work (it doesn't) (f[x_]:=y)/.y->x

Thanks in advance!

$\endgroup$
  • $\begingroup$ Maybe your question is oversimplified... I just want to point out 1. k[x_]:=Evaluate[z+y/.y->x] has the same effect as k2[x_]=z+y/.y->x and k3[x_]:=z+x. (Check DownValues/@{k,k2,k3}) 2. Function definition based on pattern matching can't be compiled directly, for more information you may want to read this. $\endgroup$ – xzczd Oct 10 '16 at 15:08
  • $\begingroup$ @xzczd You are right about the equivalence of the first two, wrong about the equivalence to the third (would be right if it was Set and not SetDelayed there): {HoldPattern[k[x_]] :> 1 + x, HoldPattern[k2[x_]] :> 1 + x, HoldPattern[k3[x_]] :> z + x} and that was precisely the point - I want to get from k[x_]:=y+z to k[x_]:=x+z rather than to k[x_] = x+z $\endgroup$ – Shwouchk Oct 10 '16 at 15:27
  • 1
    $\begingroup$ Oh, so you want y be replaced while z be unevaluated. I think this should stated in a clearer way in the body of the question. As to this specific example, a solution I can think out is: Unevaluated@(k[x_] := y + z) /. y -> x $\endgroup$ – xzczd Oct 10 '16 at 16:04
  • $\begingroup$ If I understand you correctly, is f[x_] := z + y /. y -> x too slow when used like this (z becomes a number eventually?): Plot[f[x], {x,-1,1}]? Even if that's true... I don't think I quite understand you because of the z. Can you provide a next-to-minimal example? $\endgroup$ – QuantumDot Oct 11 '16 at 2:08
  • $\begingroup$ @xzczd It appears that this is exactly what I was looking for, thanks! I will try to edit the question, and you are of course also welcome to suggest an edit. If you add the comment as an answer, I will accept it. $\endgroup$ – Shwouchk Oct 11 '16 at 12:07
3
$\begingroup$

OK, let me extend my comment to an answer. As mentioned in your question:

Ideally, this would work (it doesn't) (f[x_]:=y)/.y->x

That attempt doesn't succeed because ReplaceAll (/.) is a function that doesn't have HoldAll etc. attribute and it evaluates its argument before the replacement. To resolve the problem we need to stop the auto evaluation in some way, for example:

z = 1;

(* Solution 1 *)
Unevaluated@(k[x_] := y + z) /. y -> x

(* Solution 2 *)
Hold[k2[x_] := y + z] /. y -> x // ReleaseHold

DownValues /@ {k, k2}
(* {{HoldPattern[k[x_]] :> x + z}, {HoldPattern[k2[x_]] :> x + z}} *)
$\endgroup$
  • $\begingroup$ Thanks! came to think that it was all about the Precedence of the operators and forgot about the hold... I'm surprised there isn't a version of ReplaceAll with both a higher precedence and a hold - I guess I'll need to write one for myself. $\endgroup$ – Shwouchk Oct 11 '16 at 12:56
1
$\begingroup$

Another idea is to use Set instead of SetDelayed, and use Unevaluated to prevent evaluation:

z = 1;
f[x_] = With[{y = x}, Unevaluated @ Unevaluated[y + z]];
DownValues[f]

{HoldPattern[f[x_]] :> x + z}

$\endgroup$

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.