5
$\begingroup$

I am facing an issue when I try to reverse the arguments of a function in a replacement rule.

Let me give an example :

g[x3, x2, x1] /. {g[arg___] -> g[Sequence @@ Reverse[{arg}]]}

This outputs

g[x3,x2,x1]

Even using the built-in function

g[x3, x2, x1] /. {g[arg___] -> ReverseApplied[g][arg]}

gives the same incorrect output.

What is happening here and what is the correct way of doing this ?

$\endgroup$
1
  • 1
    $\begingroup$ The code I wrote in the post is a toy example to point out the problem, but in my program I do more complicated replacements where it needs to find a given pattern, and when it finds the pattern replace the function by itself with reversed arguments, so replacement is an important feature that I am forced to use. $\endgroup$ Apr 3 at 7:58

3 Answers 3

8
$\begingroup$
expr = g[x3, x2, x1];

You must use RuleDelayed (:>) instead of Rule

expr /. g[arg___] :> g[Sequence @@ Reverse[{arg}]]

g[x1, x2, x3]

Many other possibilities include

Cases with {0} level

First @ Cases[expr, h_[args__] :> h[Reverse[{args}]], {0}]

g[{x1, x2, x3}]

Position and Part or Query

p = Reverse @ Flatten @ Position[expr, _Symbol, Heads -> False]

{3, 2, 1}

expr[[p]]

g[x1, x2, x3]

Query[p] @ expr

g[x1, x2, x3]

$\endgroup$
6
$\begingroup$

The Rule versus RuleDelayed issue probably warrants closing this question. That is a basic distinction easily discoverable in the documentation and books and examples etc. However, there are nuances here that it might be worth discussing.

If you do this

g[x3, x2, x1] /. {g[arg___] :> ReverseApplied[g][arg]}

you need to be aware that the g expressions will be evaluated. To demonstrate, let's give g a definition:

g[a_, b_, c_] := h[a, b]

Now evaluate

g[x3, x2, x1] /. {g[arg___] :> ReverseApplied[g][arg]}
(* h[x3, x2] *)

Presumably, what we wanted to get was h[x1, x2]. So, to answer your question of "what is the correct way of doing this?", you should do what you already knew how to do: use ReverseApplied, but do it directly.

ReverseApplied[g][x3, x2, x1]
(* h[x1, x2] *)

There is no need to go through the whole replacement exercise, just apply ReverseApplied directly.

Now, if the expression g[x3, x2, x1] does not evaluate to something other than itself, then the suggested replacements based on RuleDelayed will work, but the simpler way to do it would be to simply apply Reverse:

(* I'll use gg to distinguish from the previous case *)
Reverse@gg[x3, x2, x1]
(* gg[x1, x2, x3] *)

A situation where this might make sense is if the arguments have distinct types that define a correct order. For example, let's define gg like this:

gg[a_Integer, b_String] := StringRepeat[b, a]

In the expected case we have

gg[3, "abc"]
(* "abcabcabc" *)

But maybe we somehow have gg["abc", 3] that we want to evaluate in the "obvious" way. Then we can just do

Reverse[gg["abc", 3]]
(* "abcabcabc" *)

Or, of course, we can still use the more general

ReverseApplied[gg]["abc", 3]
(* "abcabcabc" *)

which avoids having to consider whether the gg["abc", 3] expression will evaluate or not.

$\endgroup$
4
$\begingroup$

Another way to do this is as follows:

f = Apply @@ {Head@#, Reverse@*List @@ #} &;

f@g[x3, x2, x1]

g[x1, x2, x3]

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