2
{"test", 3} /. s_String :> StringReverse[s]
{"test", 3} /. s_String -> StringReverse[s]

The second line gives the error:

StringReverse: String expected at position 1 in StringReverse[s]

Question: why does it give the error with Rule, but not RuleDelayed?

EDIT: I noticed that {3, 4} /. s_ -> Sin[s] // N works without error. What is the difference?

GambitSquared
  • 2,311
  • 15
  • 23
  • Try evaluating StringReverse[s] on its own, without s having a value. – Szabolcs Aug 19 '17 at 10:16
  • @Szabolcs I think my question is different; what I didn't understand was that the rhs of a rule is calculated first... so the line is not evaluated strictly from left to right... – GambitSquared Aug 19 '17 at 10:45
  • There is no difference at all in this regard between Set and Rule. In fact the LHS is evaluated first, as you assumed. But LHS of the rule is only s_String. The /. and what comes to the left of that is not part of the rule. It's the reverse: The rule is part of the /.. Look at the full form: ReplaceAll[{"test", 3}, Rule[s_String, StringReverse[s]]]. – Szabolcs Aug 19 '17 at 11:06
  • Since neither Rule nor ReplaceAll have any (relevant) Hold* attributes, the standard evaluation sequence is followed: 1. left to right, starting with the head and continuing with arguments. 2. then apply definitions associated with the head. This means that StringReverse[s] gets evaluated before ReplaceAll has a chance to do anything with it. – Szabolcs Aug 19 '17 at 11:09
  • @Szabolcs Why does this {3, 4} /. x_ -> Sin[x] // N work without error then? Here Sin[x] is evaluated before Mathematica knows x is a real number... – GambitSquared Aug 19 '17 at 18:03
  • I've marked this topic a duplicate of 22917, let me know if you disagree. – Kuba Aug 19 '17 at 22:37
  • This goes back to my first comment ... try evaluating Sin[x] on its own ... Is there an error? Do the same with StringReverse[x] now. Is there an error? – Szabolcs Aug 20 '17 at 06:53

1 Answers1

5

If you don't use RuleDelayed, StringReverse is executed before the rest of the function. And because it expects a string as argument (and not the symbol s) it complains and goes on strike.

You can see this with

TracePrint[{"test", 3} /. s_String -> StringReverse[s], _StringReverse]

And also with

{"test", 3} /. s_String -> StringReverse["ab"]

{"ba", 3}

eldo
  • 67,911
  • 5
  • 60
  • 168
  • Why does it actually work in this case: {3, 4} /. x_ -> Sin[x] // N ? x is not know to be a real number yet here is well... – GambitSquared Aug 19 '17 at 18:00
  • @Gambit, once more: when in doubt as to how something gets evaluated, wrap the expression in Hold[] and look at the FullForm[]: FullForm[Hold[{3, 4} /. x_ -> Sin[x] // N]]. You will then see that the replacement is done before the sines are seen by N[]. – J. M.'s missing motivation Aug 19 '17 at 18:35
  • @GambitSquared, Also, note that StringReverse requires a string or list of strings as an argument,otherwise it will generate the message you see. Sin can accept numeric or symbolic arguments. – david Aug 19 '17 at 19:11