1
$\begingroup$

In the StringReplace example(chaging two letter to uppercase) below, delayed rule is used. However, the result is the same even if rule is used. 1)The delayed rule must be uesd in this case? 2)In what cases should delayed rule should be used when using StringReplace? (I've read that the rhs of the delayed rule is not calculated but held)

StringReplace[TextSentences[WikipediaData["computers"]][[1]]
,x:(Whitespace~~LetterCharacter~~LetterCharacter~~Whitespace):>ToUpperCase[x]] (*same result when "->" used instes of "->"*)

Result

A computer IS a machine that can BE programmed TO carry out sequences OF arithmetic OR logical operations (computation) automatically. 
$\endgroup$
1
  • 1
    $\begingroup$ The delayed rule localises x in the scope of StringReplace so if x previously had a value set that will not interfere with the operation. $\endgroup$ Nov 29, 2023 at 11:27

1 Answer 1

2
$\begingroup$

Yes, RuleDelayed has the attribute HoldRest, which means that the rule isn't evaluated before evaluating the whole RuleDelayed expression. Since RuleDelayed expressions are sort of just static things that get used by other functions, this effectively means that StringReplace decides what to do with it, and there is a well-defined convention among all Mathematica functions that makes it easy to predict what will happen.

We can see the differences between Rule and RuleDelayed and their different consequences by considering the following examples. In a fresh session (in particular, make sure that x has no definition), evaluate these separately:

(* 1 *)
x : LetterCharacter -> x <> x
(* x : LetterCharacter -> x <> x *)

(* 2 *)
x : LetterCharacter :> x <> x
(* x : LetterCharacter :> x <> x *)

#2 just outputs itself, because the HoldRest keeps the right hand side unevaluated and evaluating the left hand side doesn't change anything. #1 will produce error messages, because StringJoin doesn't operate on symbols. But, crucially, the StringJoin expression outputs itself. This is the standard behavior. In general, Mathematica evaluation does not produce error-type structures as output. It generates messages, but the actual output is just the input expression left unevaluated. The consequence in this case is that there is no effective difference between Rule and RuleDelayed in this case if these rules were to be used in StringReplace:

StringReplace["abc", x : LetterCharacter -> x <> x]
(* Error messages produced, but the output is
   "aabbcc" *)

StringReplace["abc", x : LetterCharacter :> x <> x]
(* No error messages, and the output is the same
   aabbcc *)

So, #1 worked by accident. Now try these:

x = "Z"

(* 3 *)
x : LetterCharacter -> x <> x
(* x : LetterCharacter -> "ZZ" *)

(* 4 *)
x : LetterCharacter :> x <> x
(* x : LetterCharacter :> x <> x *)

#3 is the same as #1 and #4 is the same as #2, but in the intervening time we've set x = "Z". And you can predict what will happen:

StringReplace["abc", x : LetterCharacter -> x <> x]
(* "ZZZZZZ" *)

StringReplace["abc", x : LetterCharacter :> x <> x]
(* "aabbcc" *)

Now, in your specific use case with ToUpper[x] we're basically in case #2. But if you replaced the RuleDelayed with just Rule, we'd be in case #1. One difference between ToUpper and StringJoin is that ToUpper doesn't emit error messages for non-string inputs. So, your case with Rule would work by accident in the same way that #1 did, but would do so silently. Let's try (simplified to avoid accessing wikipedia):

StringReplace["a bc d", x : (Whitespace ~~ LetterCharacter ~~ LetterCharacter ~~ Whitespace) -> ToUpperCase[x]]
(* "a BC d" *)

x = "apple"

StringReplace["a bc d", x : (Whitespace ~~ LetterCharacter ~~ LetterCharacter ~~ Whitespace) -> ToUpperCase[x]]
(* "aAPPLEd" *)

The upshot of all this is that a fairly safe, if simplistic, rule of thumb is to use RuleDelayed whenever you are naming your patterns (and presumably using those names in the computations on the right hand side). This protects you from accidentally using pre-existing definitions (it's effectively "localizing" the symbols). It also avoids (usually) misunderstanding what your rule will actually do since it holds evaluation until the rule gets used.

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