Concatenated rule applications (applying rules to rules correctly)

I am trying to apply a series of individual rules onto an expression sequentially, but also not have to write out the repeated ReplaceAll functions each time I want to perform the same series of rules.

Here’s an illustrative example of my problem:

(* r1, r2 and r3 are the individual rule transformations *)
r1[a_] := {a :> 3 a};
r2[a_] := {a :> -a};
r3[a_] := {a :> a + 1};

(* Try to define a single rule operator which applies rules in a given order *)
rall[a_] := r1[a] /. r2[a] /. r3[a];

(* Ideal answer is given by *)
a /. r1[a] /. r2[a] /. r3[a]

Which evaluates to -3(a+1), applying each rule sequentially, whereas

a /. rall[a]

evaluates to a, having not applied any of the rules. This can be understood, since rall[a] evaluates to {-a-1:>3(-(a+1))}, having applied the rules r2[a] and r3[a] to the initial r1[a] term, not just the rhs instances of a in the rules expressions.

How can I build a composite rule function that achieves my aim? Is there a way to delay the evaluation of the rules stated in rall[a] until I apply it to a variable?




Functions are already based on replacement rules. You could write: r1[a_] := 3a; r2[a_] := -a; r3[a_] := a+1; rall[a_] := r3@r2@r1[a], then try and evaluate rall[a].
– MarcoB
Jun 17 ’15 at 21:51



Well, obviously the logic of defining rall[a_] as you did it, is flawed. You instruct the second and third rule to act on the first, instead of all rules to act on some expression – and that is what you get. Why not doing something like rall[a_] := Function[expr, expr /. r1[a] /. r2[a] /. r3[a]];, and then rall[a][a]?
– Leonid Shifrin
Jun 17 ’15 at 21:51


1 Answer


Maybe with the help of Fold or FoldList :

See what happens here:

FoldList[#1 /. #2 &, a, {r1[a], r2[a], r3[a]}]

{a, 3 a, -3 a, -3 (1 + a)}

Replace FoldList with Fold to get directly the last result.

In other words:

rall[a_] := Fold[#1 /. #2 &, a, {r1[a], r2[a], r3[a]}]



-3 (1 + a)



That’s great. How do I extend this to multiple rule arguments, say for r1[a,b]? I tried some variations on syntax such as Fold[{#1,#2}/.#3 &[a,b], {r1[a,b],r2[a,b],r3[a,b]}] but can’t seem to find the correct extension.
– SLesslyTall
Jun 18 ’15 at 8:49



@SLesslyTall Simply Fold[#1 /. #2 &, expr[a,b], {r1[a, b], r2[a, b], r3[a, b]}] where expr[a,b] stands for any initial expression you want to replace, for example Sin[a]^b, or any list {a,b,a*b^2,…}, …
– SquareOne
Jun 18 ’15 at 12:32