2
 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]]
Kuba
  • 136,707
  • 13
  • 279
  • 740
Lance
  • 21
  • 1
  • 3
    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. – march Feb 21 '18 at 18:03
  • 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. – march Feb 21 '18 at 18:09
  • @march Thanks. What really confused me was that Module didn't work to scope that variable. I will use Block as you suggested. – Lance Feb 21 '18 at 20:23
  • @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. – Lance Feb 21 '18 at 20:30
  • 1
    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. – march Feb 22 '18 at 04:41

1 Answers1

1

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

Kuba
  • 136,707
  • 13
  • 279
  • 740