2
$\begingroup$
 Clear[x]
 StringCases["abcadcacb","a"~~x_~~"c"->x]
{b,d}
 x=99;
 StringCases["abcadcacb","a"~~x_~~"c"->x]
{99,99}

This fails even if x is local in a Module

Module[{x}, StringCases["abcadcacb", "a" ~~ x_ ~~ "c" -> x]]
$\endgroup$
5
  • 3
    $\begingroup$ I mean, most functions in Mathematica don't scope their variables. But you can use RuleDelayed (:>) instead of Rule (->) to fix this problem. Also, I'm not entirely sure why Module doesn't work in this case, but Block does, for good reasons: Block's purpose is to locally scope variables that have definitions elsewhere. $\endgroup$
    – march
    Commented Feb 21, 2018 at 18:03
  • $\begingroup$ By the way, the problem isn't that x is not locally scoped in the string expression, because it is. Evaluate "x" after x=99 to see that this is true. The problem is that the x at the end of the Rule is not locally scoped. $\endgroup$
    – march
    Commented Feb 21, 2018 at 18:09
  • $\begingroup$ @march Thanks. What really confused me was that Module didn't work to scope that variable. I will use Block as you suggested. $\endgroup$
    – Lance
    Commented Feb 21, 2018 at 20:23
  • $\begingroup$ @march I guess you should alway RuleDelayed in this case, because, in general, you will never know when you are changing a value inadvertently. Maybe the Mathematica documentation should use RuleDelayed in the examples instead of Rule. $\endgroup$
    – Lance
    Commented Feb 21, 2018 at 20:30
  • 1
    $\begingroup$ For me, I almost always use RuleDelayed when replacing expression via patterns. I only use Rule when I'm replacing an expression with something that doesn't depend on that pattern. There are use cases for both, but RuleDelayed allows you to circumvent these scoping problems for the most part, and you can always inject an expression into the right-hand side of a delayed rule using the With scoping construct. Still, the implementation of Module here is a little wired to me. $\endgroup$
    – march
    Commented Feb 22, 2018 at 4:41

1 Answer 1

1
$\begingroup$

Why x_->x causes problems is explained in:

Unexpected behavior of rule matching a pattern

Shortly, use :>.

Why Module fails to help? While Rule is not a scoping construct it is considered one by Module. Which means x inside will not be scoped by Module if x_ appears in a left hand side of rule.:

Module[{x},
  Hold @ Column @ {
    Rule[x_, x]
  , RuleDelayed[x_, x]
  , Module[{x}, x]
  , DirectedEdge[x_, x]
  , foo[x_, x]
  , Rule[y_, y x]}
 ]

enter image description here

Relevant part of docs:

Symbols that occur as pattern names in lhs are treated as local to the rule. This is true when the symbols appear on the right-hand side of /; conditions in lhs, and when the symbols appear anywhere in rhs, even inside other scoping constructs.

ref/Rule/Details

About issues with nested scoping constructs you can take a look at:

Enforcing correct variable bindings and avoiding renamings for conflicting variables in nested scoping constructs

which also explains the last example with y_->y x.

Also related:

Unexpected behavior of rule matching a pattern

$\endgroup$

Your Answer

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

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