5
$\begingroup$

I get what I expect from the following code

Replace[{a, b, c}, b_ -> (w /; x > b), {1}]
(* {w /; x > a, w /; x > b, w /; x > c} *)

However, when I change Rule to RuleDelayed, then I get a different result

Replace[{a, b, c}, b_ :> (w /; x > b), {1}]
(* {a, b, c} *)

I would expect that if the Condition was part of the pattern b_ /; x > b :> w, but why does Condition condition the replacement when it is in the replacement expression?

How to prevent Condition from conditioning when it is part of the replacement expression in RuleDelayed?

$\endgroup$
3
$\begingroup$

I think the first case, the one with Rule, is actually the peculiar result. Condition is a special pattern-matching operator and does not normally remain verbatim in a replacement but rather affects the replacement itself.

The tutorial Putting Constraints on Patterns says, emphasis mine:

You can use /; on whole definitions and transformation rules, as well as on individual patterns. In general, you can put /;condition at the end of any := definition or :> rule to tell the Wolfram Language that the definition or rule applies only when the specified condition holds. Note that /; conditions should not usually be put at the end of = definitions or -> rules, since they will then be evaluated immediately, as discussed in "Immediate and Delayed Definitions".

Consider these examples using Set and SetDelayed as proxy for Rule and RuleDelayed for the sake of convenience.

f[x_]  = "yes" /; x > 3;
g[x_] := "yes" /; x > 3;
ff[x_] /; x > 3  = "yes";
gg[x_] /; x > 3 := "yes";

Array[f, 5]
Array[g, 5]
Array[ff, 5]
Array[gg, 5]
{"yes" /; 1 > 3, "yes" /; 2 > 3, "yes" /; 3 > 3, "yes" /; 4 > 3, "yes" /; 5 > 3}

{g[1], g[2], g[3], "yes", "yes"}

{ff[1], ff[2], ff[3], "yes", "yes"}

{gg[1], gg[2], gg[3], "yes", "yes"}

Note that in all but the first function f it is recognized that the pattern does not match e.g. g[2] and the rule is not applied.

It may be in your case that Rule is actually the tool you want, or you may need to make Condition appear inert to the pattern matcher in some way, e.g.

h[x_] := Condition @@ Hold["yes", x > 3]

Array[h, 5]
{"yes" /; 1 > 3, "yes" /; 2 > 3, "yes" /; 3 > 3, "yes" /; 4 > 3, "yes" /; 5 > 3}

Because Condition has HoldAll your initial use of Rule is "safe" in that the pattern variable b is protected from global assignments, therefore I recommend that you continue using -> if this is representative of your application, i.e. Condition is the Head of the RHS of the rule. If it is not your problem (when using :> or :=) goes away because the pattern matcher does not see it:

f2[x_] := {2 x /; x > 3}    (* RHS Head is List rather than Condition *)

Array[f2, 5]
{{2 /; 1 > 3}, {4 /; 2 > 3}, {6 /; 3 > 3}, {8 /; 4 > 3}, {10 /; 5 > 3}}

That head may be Identity which in normal evaluation disappears, leaving only the verbatim Condition expression. Applied to your original example:

Replace[{a, b, c}, b_ :> Identity[w /; x > b], {1}]
{w /; x > a, w /; x > b, w /; x > c}

However I would not recommend this as it will not interact "well" with held expressions. Compare:

Replace[Hold[a, b, c], b_ :> Identity[w /; x > b], {1}]

Replace[Hold[a, b, c], b_ -> (w /; x > b), {1}]
Hold[Identity[w /; x > a], Identity[w /; x > b], Identity[w /; x > c]]

Hold[w /; x > a, w /; x > b, w /; x > c]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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