2
$\begingroup$

I apologize if the title is too vague/general but I couldn't find a better one. I am trying to use either Module or With but it does not work if the object containing the local variables is defined outside of Module or With. Here is an example that does not work:

f = Cos[qx + qy];
With[{qy = qx},
f
]

which gives:

Cos[qx + qy]

but this obviously works:

With[{qy = qx},
Cos[qx + qy]
]

and gives:

Cos[2 qx]

What am I missing? I could define f as a function and that would work. But I would like to understand why this scoping does not work while it works in other languages.

$\endgroup$
  • 1
    $\begingroup$ Try With[{qy = qx}, Evaluate[f]] $\endgroup$ – roman465 Jun 21 '18 at 21:41
  • $\begingroup$ Thanks that works! Do you know why it doesn't work without the Evaluate? $\endgroup$ – Karim Jun 21 '18 at 22:01
  • $\begingroup$ I'm not sure how to explain it properly. You can use Trace to look at the evaluation process of both with and without Evaluate. $\endgroup$ – roman465 Jun 21 '18 at 22:09
  • 1
    $\begingroup$ See What are the use cases for different scoping constructs? for extended discussion about With/Module/Block scoping. $\endgroup$ – WReach Jun 21 '18 at 22:36
  • $\begingroup$ Thanks. I will have a look at that. $\endgroup$ – Karim Jun 25 '18 at 8:57
7
$\begingroup$

This arises out of how Mathematica scopes variables. With and Module use lexical scoping, which is to say they scope the variables by name as they see them. Block uses dynamic scoping, which captures and resets the value of the Symbol.

This input might help explain it:

f = Cos[qx + qy];
Module[{qy = qx},
 {f, qy, Hold[qy]}
 ]

{Cos[qx + qy], qx, Hold[qy$113564]}

Every explicit instance of qy in the body has been renamed to qy$113564 and that has been given the value qx. Then f is evaluated.

Because of this ordering the qy in f doesn't see the Module variable qy$113564.

On the other hand this will work:

Block[{qy = qx},
 {f, qy, Hold[qy]}
 ]

{Cos[2 qx], qx, Hold[qy]}

Because Block reassigns the value of qy directly without any renaming.

Finally, returning to your case at hand:

f = Cos[qx + qy];
With[{qy = qx},
 {f, qy, Hold[qy]}
 ]

{Cos[qx + qy], qx, Hold[qx]}

With injects the value qx anywhere it sees qy exactly by name in its body. Evaluate forces the body to have an explicit qy in it for With to see.

These different scoping constructs are very powerful and Leonid has a few nice posts on how they can be most effectively used.

$\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.