Skip to main content
Corrected a misleading sentence / statement
Source Link
Leonid Shifrin
  • 115.8k
  • 16
  • 341
  • 435

The basic idea is to exploit the semantics of rules with local variables shared between the body of With and the condition, but within the context of local rules. Since the condition is True, it forced theThe eval variable towill be evaluated first (regardless of whether the condition ends up being True - as in this case, or False - thanks to @luyuwuli for pointing out the problem in the original wording for this part) , inside the declaration part of With, while the code inside the Condition , here the body of With (g[eval]), is treated then as normally the r.h.s. of RuleDelayed is. It is important that With is used, since it can inject into unevaluated expressions. Module and Block also have the shared variable semantics, but wouldn't work here: while their declaration part would evaluate, they would not be able to communicate that result to their body that remains unevaluated (more precisely, only the part of the body that is inside Condition will remain unevaluated - see below). The body of With above was not evaluated either, however With injects the evaluated part ( eval here) into it - this is why the g function above remained unevaluated when the rule applied. This can be further illustrated by the following:

The basic idea is to exploit the semantics of rules with local variables shared between the body of With and the condition, but within the context of local rules. Since the condition is True, it forced the eval variable to be evaluated inside the declaration part of With, while the code inside the Condition , here the body of With (g[eval]), is treated then as normally the r.h.s. of RuleDelayed is. It is important that With is used, since it can inject into unevaluated expressions. Module and Block also have the shared variable semantics, but wouldn't work here: while their declaration part would evaluate, they would not be able to communicate that result to their body that remains unevaluated (more precisely, only the part of the body that is inside Condition will remain unevaluated - see below). The body of With above was not evaluated either, however With injects the evaluated part ( eval here) into it - this is why the g function above remained unevaluated when the rule applied. This can be further illustrated by the following:

The basic idea is to exploit the semantics of rules with local variables shared between the body of With and the condition, but within the context of local rules. The eval variable will be evaluated first (regardless of whether the condition ends up being True - as in this case, or False - thanks to @luyuwuli for pointing out the problem in the original wording for this part) , inside the declaration part of With, while the code inside the Condition , here the body of With (g[eval]), is treated then as normally the r.h.s. of RuleDelayed is. It is important that With is used, since it can inject into unevaluated expressions. Module and Block also have the shared variable semantics, but wouldn't work here: while their declaration part would evaluate, they would not be able to communicate that result to their body that remains unevaluated (more precisely, only the part of the body that is inside Condition will remain unevaluated - see below). The body of With above was not evaluated either, however With injects the evaluated part ( eval here) into it - this is why the g function above remained unevaluated when the rule applied. This can be further illustrated by the following:

Fixed a broken link
Source Link
Leonid Shifrin
  • 115.8k
  • 16
  • 341
  • 435

Generally, you want the Trott-StrzebonskiTrott-Strzebonski in-place evaluation technique:

f[x_Real]:=x^2; Hold[{Hold[2.],Hold[3.]}]/.n_Real:>With[{eval = f[n]},eval/;True] (* Hold[{Hold[4.],Hold[9.]}] *) 

It will inject the evaluated r.h.s. into an arbitrarily deep location in the held expression, where the expression was found that matched the rule pattern. This is in contrast with Evaluate, which is only effective on the first level inside Hold (won't work in the example above). Note that you may evaluate some things and not evaluate others:

g[x_] := x^3; Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = f[n]}, g[eval] /; True] (* Hold[{Hold[g[4.]], Hold[g[9.]]}] *) 

The basic idea is to exploit the semantics of rules with local variables shared between the body of With and the condition, but within the context of local rules. Since the condition is True, it forced the eval variable to be evaluated inside the declaration part of With, while the code inside the Condition , here the body of With (g[eval]), is treated then as normally the r.h.s. of RuleDelayed is. It is important that With is used, since it can inject into unevaluated expressions. Module and Block also have the shared variable semantics, but wouldn't work here: while their declaration part would evaluate, they would not be able to communicate that result to their body that remains unevaluated (more precisely, only the part of the body that is inside Condition will remain unevaluated - see below). The body of With above was not evaluated either, however With injects the evaluated part ( eval here) into it - this is why the g function above remained unevaluated when the rule applied. This can be further illustrated by the following:

Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval=f[n]}, With[{eval = eval},g[eval]/;True]] (* Hold[{Hold[g[4.]],Hold[g[9.]]}] *) 

Note b.t.w. that only the part of code inside With that is inside Condition is considered a part of the "composite rule" and therefore not evaluated. So,

Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]}, With[{eval = eval},Print[eval];g[eval]/;True]] (* print: 4. *) (* print: 9. *) (* Hold[{Hold[g[4.]],Hold[g[9.]]}] *) 

But

Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]}, With[{eval = eval},(Print[eval];g[eval])/;True]] (* Hold[{Hold[Print[4.];g[4.]],Hold[Print[9.];g[9.]]}] *) 

This should further clarify this mechanism.

Generally, you want the Trott-Strzebonski in-place evaluation technique:

f[x_Real]:=x^2; Hold[{Hold[2.],Hold[3.]}]/.n_Real:>With[{eval = f[n]},eval/;True] (* Hold[{Hold[4.],Hold[9.]}] *) 

It will inject the evaluated r.h.s. into an arbitrarily deep location in the held expression, where the expression was found that matched the rule pattern. This is in contrast with Evaluate, which is only effective on the first level inside Hold (won't work in the example above). Note that you may evaluate some things and not evaluate others:

g[x_] := x^3; Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = f[n]}, g[eval] /; True] (* Hold[{Hold[g[4.]], Hold[g[9.]]}] *) 

The basic idea is to exploit the semantics of rules with local variables shared between the body of With and the condition, but within the context of local rules. Since the condition is True, it forced the eval variable to be evaluated inside the declaration part of With, while the code inside the Condition , here the body of With (g[eval]), is treated then as normally the r.h.s. of RuleDelayed is. It is important that With is used, since it can inject into unevaluated expressions. Module and Block also have the shared variable semantics, but wouldn't work here: while their declaration part would evaluate, they would not be able to communicate that result to their body that remains unevaluated (more precisely, only the part of the body that is inside Condition will remain unevaluated - see below). The body of With above was not evaluated either, however With injects the evaluated part ( eval here) into it - this is why the g function above remained unevaluated when the rule applied. This can be further illustrated by the following:

Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval=f[n]}, With[{eval = eval},g[eval]/;True]] (* Hold[{Hold[g[4.]],Hold[g[9.]]}] *) 

Note b.t.w. that only the part of code inside With that is inside Condition is considered a part of the "composite rule" and therefore not evaluated. So,

Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]}, With[{eval = eval},Print[eval];g[eval]/;True]] (* print: 4. *) (* print: 9. *) (* Hold[{Hold[g[4.]],Hold[g[9.]]}] *) 

But

Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]}, With[{eval = eval},(Print[eval];g[eval])/;True]] (* Hold[{Hold[Print[4.];g[4.]],Hold[Print[9.];g[9.]]}] *) 

This should further clarify this mechanism.

Generally, you want the Trott-Strzebonski in-place evaluation technique:

f[x_Real]:=x^2; Hold[{Hold[2.],Hold[3.]}]/.n_Real:>With[{eval = f[n]},eval/;True] (* Hold[{Hold[4.],Hold[9.]}] *) 

It will inject the evaluated r.h.s. into an arbitrarily deep location in the held expression, where the expression was found that matched the rule pattern. This is in contrast with Evaluate, which is only effective on the first level inside Hold (won't work in the example above). Note that you may evaluate some things and not evaluate others:

g[x_] := x^3; Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = f[n]}, g[eval] /; True] (* Hold[{Hold[g[4.]], Hold[g[9.]]}] *) 

The basic idea is to exploit the semantics of rules with local variables shared between the body of With and the condition, but within the context of local rules. Since the condition is True, it forced the eval variable to be evaluated inside the declaration part of With, while the code inside the Condition , here the body of With (g[eval]), is treated then as normally the r.h.s. of RuleDelayed is. It is important that With is used, since it can inject into unevaluated expressions. Module and Block also have the shared variable semantics, but wouldn't work here: while their declaration part would evaluate, they would not be able to communicate that result to their body that remains unevaluated (more precisely, only the part of the body that is inside Condition will remain unevaluated - see below). The body of With above was not evaluated either, however With injects the evaluated part ( eval here) into it - this is why the g function above remained unevaluated when the rule applied. This can be further illustrated by the following:

Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval=f[n]}, With[{eval = eval},g[eval]/;True]] (* Hold[{Hold[g[4.]],Hold[g[9.]]}] *) 

Note b.t.w. that only the part of code inside With that is inside Condition is considered a part of the "composite rule" and therefore not evaluated. So,

Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]}, With[{eval = eval},Print[eval];g[eval]/;True]] (* print: 4. *) (* print: 9. *) (* Hold[{Hold[g[4.]],Hold[g[9.]]}] *) 

But

Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]}, With[{eval = eval},(Print[eval];g[eval])/;True]] (* Hold[{Hold[Print[4.];g[4.]],Hold[Print[9.];g[9.]]}] *) 

This should further clarify this mechanism.

Made notation more standard, consistent with Leonids style
Source Link
Jacob Akkerboom
  • 12.3k
  • 47
  • 87
In[47]:= f[x_Real]:=x^2; Hold[{Hold[2.],Hold[3.]}]/.n_Real:>With[{eval = f[n]},eval/;True] Out[48]=(* Hold[{Hold[4.],Hold[9.]}] *) 
In[49]:= g[x_] := x^3; Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = f[n]}, g[eval] /; True] Out[50]=(* Hold[{Hold[g[4.]], Hold[g[9.]]}] *) 

The basic idea is to exploit the semantics of rules with local variables shared between the body of WithWith and the condition, but within the context of local rules. Since the condition is True, it forced the eval variable to be evaluated inside the declaration part of With, while the code inside the Condition -, here the body of With (g[eval]), isis treated then as normally the r.h.s. of RuleDelayed is. It is important that With is used, since it can inject into unevaluated expressions. Module and Block also have the shared variable semantics, but wouldn't work here: while their declaration part would evaluate, they would not be able to communicate that result to their body that remains unevaluated (more precisely, only the part of the body that is inside Condition will remain unevaluated - see below). The body of With above was not evaluated either, however With injects the evaluated part ( eval here) into it - this is why the g function above remained unevaluated when the rule applied. This can be further illustrated by the following:

In[51]:= Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval=f[n]}, With[{eval = eval},g[eval]/;True]] Out[51]=(* Hold[{Hold[g[4.]],Hold[g[9.]]}] *) 
In[10]:= Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]},   With[{eval = eval},Print[eval];g[eval]/;True]] During evaluation of(* In[10]print:= 4. During evaluation of*) (* In[10]print:= 9. *) Out[10]=(* Hold[{Hold[g[4.]],Hold[g[9.]]}] *) 
In[11]:= Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]}, With[{eval = eval},(Print[eval];g[eval])/;True]] Out[11]=(* Hold[{Hold[Print[4.];g[4.]],Hold[Print[9.];g[9.]]}] *) 
In[47]:= f[x_Real]:=x^2; Hold[{Hold[2.],Hold[3.]}]/.n_Real:>With[{eval = f[n]},eval/;True] Out[48]= Hold[{Hold[4.],Hold[9.]}] 
In[49]:= g[x_] := x^3; Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = f[n]}, g[eval] /; True] Out[50]= Hold[{Hold[g[4.]], Hold[g[9.]]}] 

The basic idea is to exploit the semantics of rules with local variables shared between the body of With and the condition, but within the context of local rules. Since the condition is True, it forced the eval variable to be evaluated inside the declaration part of With, while the code inside the Condition - here the body of With (g[eval]), is treated then as normally the r.h.s. of RuleDelayed is. It is important that With is used, since it can inject into unevaluated expressions. Module and Block also have the shared variable semantics, but wouldn't work here: while their declaration part would evaluate, they would not be able to communicate that result to their body that remains unevaluated (more precisely, only the part of the body that is inside Condition will remain unevaluated - see below). The body of With above was not evaluated either, however With injects the evaluated part ( eval here) into it - this is why the g function above remained unevaluated when the rule applied. This can be further illustrated by the following:

In[51]:= Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval=f[n]}, With[{eval = eval},g[eval]/;True]] Out[51]= Hold[{Hold[g[4.]],Hold[g[9.]]}] 
In[10]:= Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]},   With[{eval = eval},Print[eval];g[eval]/;True]] During evaluation of In[10]:= 4. During evaluation of In[10]:= 9. Out[10]= Hold[{Hold[g[4.]],Hold[g[9.]]}] 
In[11]:= Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]}, With[{eval = eval},(Print[eval];g[eval])/;True]] Out[11]= Hold[{Hold[Print[4.];g[4.]],Hold[Print[9.];g[9.]]}] 
f[x_Real]:=x^2; Hold[{Hold[2.],Hold[3.]}]/.n_Real:>With[{eval = f[n]},eval/;True] (* Hold[{Hold[4.],Hold[9.]}] *) 
g[x_] := x^3; Hold[{Hold[2.], Hold[3.]}] /. n_Real :> With[{eval = f[n]}, g[eval] /; True] (* Hold[{Hold[g[4.]], Hold[g[9.]]}] *) 

The basic idea is to exploit the semantics of rules with local variables shared between the body of With and the condition, but within the context of local rules. Since the condition is True, it forced the eval variable to be evaluated inside the declaration part of With, while the code inside the Condition , here the body of With (g[eval]), is treated then as normally the r.h.s. of RuleDelayed is. It is important that With is used, since it can inject into unevaluated expressions. Module and Block also have the shared variable semantics, but wouldn't work here: while their declaration part would evaluate, they would not be able to communicate that result to their body that remains unevaluated (more precisely, only the part of the body that is inside Condition will remain unevaluated - see below). The body of With above was not evaluated either, however With injects the evaluated part ( eval here) into it - this is why the g function above remained unevaluated when the rule applied. This can be further illustrated by the following:

Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval=f[n]}, With[{eval = eval},g[eval]/;True]] (* Hold[{Hold[g[4.]],Hold[g[9.]]}] *) 
Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]}, With[{eval = eval},Print[eval];g[eval]/;True]] (* print: 4. *) (* print: 9. *) (* Hold[{Hold[g[4.]],Hold[g[9.]]}] *) 
Hold[{Hold[2.],Hold[3.]}]/.n_Real:>Module[{eval = f[n]}, With[{eval = eval},(Print[eval];g[eval])/;True]] (* Hold[{Hold[Print[4.];g[4.]],Hold[Print[9.];g[9.]]}] *) 
Post Migrated Here from stackoverflow.com (revisions)
Source Link
Leonid Shifrin
  • 115.8k
  • 16
  • 341
  • 435
Loading