3
$\begingroup$

The mathematica front-end colors x on the right hand side of x_ :> x and f[x_] := x but not with x_ -> x and f[x_] = x.

But, at least if x is not defined at the time the replacement rule is created, the x in the latter cases also refers to whatever matched the labeled pattern, e.g. in

f@x_ = Integrate[y^2, {y, 0, x}]
f@3

or even

ClearAll@x
f@x_ = Integrate[y^2, {y, 0, x}]
x = 10;
f@3

with the same result. And (9 /. x_ -> x^2) === 81.

I always felt the syntax highlighting suggested that this is not possible, that somehow the pattern name would be ignored, such that 9 /. x_ -> x^2 would give x^2, symbolically.

Certainly it is not very safe in many cases, but still.

Bottom line is, we can sometimes use e.g. f@x_ = Integrate[y^2, {y, 0, x}] instead of f@x_ := Evaluate@Integrate[y^2, {y, 0, x}].

Am I missing something or is this really how things work?


I would like to wrap such things as f@x_ = Integrate[y^2, {y, 0, x}] in a Module to make the x a safe, unique label, but that doesn't seem to work for some reason. That is, I would want to write

f@x_ := Evaluate@Integrate[y^2, {y, 0, x}]

as

x = 10;(*should not matter*)
Module[{x},
 f@x_ = Integrate[
   y^2, {y, 0, x}](*I would like this x to be the one from Module*)
 ]
f@0(*should give 0*)

See How to scope `Pattern` labels in rules/set?


Appendix

This makes the intended definition of f, regardless of whether x is already set or not:

ClearAll[f, x];
x = 10;
ReleaseHold[Hold[

   f@x_ = Integrate[y^2, {y, 0, x}]

   ] /. HoldPattern@x -> Unique[Unevaluated@x]]
?f

Note also that

f@x_ = Unevaluated@Integrate[y^2, {y, 0, x}];

is effectively equivalent to

f@x_ := Integrate[y^2, {y, 0, x}];

But these definitions will recompute the integral every time.

$\endgroup$

1 Answer 1

4
$\begingroup$

From the scoping point of view the variables on the RHS of an immediate (Set) assignment aren't scoped at the evaluation time because they can evaluate to their global values. So it is completely correct that they aren't highlighted as local variables. It doesn't matter that after evaluation these variables may be scoped if global values for them were not defined at the evaluation time: Mathematica provides many different ways to construct rules with scoping using scoping constructs or without using them. What really matters is that with the current highlighting you have an indicator whether variables will be scoped at the evaluation time or not.

Of course there are ways to fool scoping constructs (and hence the syntax highlighter), for example Evaluate in f@x_ := Evaluate@x will break scoping of SetDelayed and evaluate the RHS with global definition to x (note that x on the RHS is incorrectly highlighted in a Notebook as a local variable):

x=1;
f@x_ := Evaluate@x
Definition@f

f[x_] := 1

Similarly Unevaluated in f@x_ = Unevaluated@x will prevent evaluation of x during creation of the definition for f, but won't prevent returning unscoped x as the result of evaluation of Set (the Unevaluated wrapper is "eated" by Set):

x = 1;
f@x_ = Unevaluated@x
Definition@f
1

f[x_] = x

Note that in the latter example x on the RHS is incorrectly highlighted as a global variable although it is correctly scoped thanks to Unevaluated. Only after going beyond the scope x becomes global like in the following example:

x = 1;
Block[{x}, Print[x]; x]

x

1

So you shouldn't completely trust syntax highlighter: it can't detect special cases like the mentioned above, and serves just as a simple indicator without any warranty. But it is indeed useful and helps to correct stupid misprints "on the fly" while you writing the code.


I would like to wrap such things as f@x_ = Integrate[y^2, {y, 0, x}] in a Module to make the x a safe, unique label, but that doesn't seem to work for some reason.

Exactly for this purpose there are formal symbols in Mathematica to which you can't make assignments (due to the Protected attribute):

x = 10;
f@\[FormalX]_ = Integrate[y^2, {y, 0, \[FormalX]}]
\[FormalX]^3/3

Note that inside of a Notebook formal symbols look pretty well.


Note also that immediate and delayed definitions are different not only in the evaluation but also in how they are stored and can be accessed later. Citing an old comment by Leonid Shifrin,

There is one very important use case where it makes a real difference what was used in assignment - Set or SetDelayed: the Part assignment. Confront tst = {1, 2, 3}; tst[[2]] = 5; tst (works all right) with tst1 := {1, 2, 3}; tst1[[2]] = 5 (gives assignment error, "no immediate value" for tst1). And of course, OwnValues for tst and tst1 look the same, just as you observed. Given your observation on memory consumption, I'd guess that delayed definitions may use some intermediate internal variables, while immediate ones point straight to the memory where the data is stored.

(you can be interested in reading the complete discussion on the differences between Set and SetDelayed.)

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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