12
$\begingroup$

I've seen the operation described in the title before (basically, swap the heads of the first two levels of an expression), but I can't find it...

Does anyone know the function (or idiom/incantation) for the operation I'm talking about?


Note that, in general, Thread doesn't do the described operation. E.g.:

Thread[X[Y[1, 2, 3]], Y] 

evaluates to

Y[X[1], X[2], X[3]] 

rather than the desired

Y[X[1, 2, 3]] 

The same thing goes for Map:

Map[X, Y[1, 2, 3]] (* Y[X[1], X[2], X[3]] *) 

I've tried many, many, many, many, many possibilities: Transpose[X[Y[1, 2, 3]], {1, 0}], Outer[X, Y[1, 2, 3], 0, Heads -> True], etc., etc.... without success, of course.

$\endgroup$
6
  • $\begingroup$ Would a straightforward ReplaceAll not be sufficient? $\endgroup$ Commented Jun 13, 2015 at 21:02
  • $\begingroup$ @YvesKlett: when I tried replace-based solutions I didn't succeed... I'll try again some more. $\endgroup$ Commented Jun 13, 2015 at 21:03
  • 2
    $\begingroup$ /. a_[b_[c___]] :> b[a[c]] for arbitrary fn names... $\endgroup$ Commented Jun 13, 2015 at 21:08
  • $\begingroup$ @YvesKlett: I remember now: I was trying to find a solution that was agnostic about the heads in question, and every replacement-based solution I could come up with required me to hard-code the specific heads I wanted to swap. On the other hand, I can't program Mathematica patterns to save my life, so I tend to stay clear of them as much as I can... $\endgroup$ Commented Jun 13, 2015 at 21:08
  • $\begingroup$ @ciao: thanks, I think that the :> is what I was missing... $\endgroup$ Commented Jun 13, 2015 at 21:09

4 Answers 4

13
$\begingroup$
f[x_[y_[z___]]] := y[x[z]] f[X[Y[a, b, c, d]]] 
Y[X[a, b, c, d]] 
$\endgroup$
2
  • $\begingroup$ Thank you! I thought I once came across a remark in the docs to the effect that some built-in function could be easily used to do this head-swapping operation, and in fact it was routinely used for this... I'll wait a bit longer to see if my memory is not tricking me. But if it is, then your solution shows that it's trivial to roll one's own. $\endgroup$ Commented Jun 13, 2015 at 21:23
  • $\begingroup$ @kjo, {X,Y} = {Y,X} will swap values. maybe this is the remark you've confused with your question? $\endgroup$ Commented Jun 14, 2015 at 5:45
6
$\begingroup$

One way is to use ReplaceAll, as suggested by Yves. For example:

f[g[x]] /. {f -> g, g -> f} g[f[x]] 

f[g[x]] /. {g -> f, f -> g} works too.

$\endgroup$
4
  • $\begingroup$ Compared to /. f_[g_[x___]] -> g[f[x]] the drawback would be that the function names need to be known in advance $\endgroup$ Commented Jun 13, 2015 at 21:23
  • 2
    $\begingroup$ In addition to what Yves said, I think OP wanted only the outer two heads to be swapped. So for f[g[f[g[x]]]], the desired output would be g[f[f[g[x]]]] rather than g[f[g[f[x]]]] which this answer returns. $\endgroup$ Commented Jun 13, 2015 at 22:06
  • 3
    $\begingroup$ @TheToad you do have a wicked sense for potential bugs - as befits any proud amphibian ;-) $\endgroup$ Commented Jun 13, 2015 at 22:22
  • 1
    $\begingroup$ In the case of @The Toad's example, the fix is to use Replace[] instead: Replace[f[g[f[g[x]]]], {f -> g, g -> f}, 2, Heads -> True]. $\endgroup$ Commented Jun 14, 2015 at 0:07
5
$\begingroup$

Remembering that [[0]] returns the head of an expression you could do something like

(#[[1, 0]]@(#[[0]] @@ #[[1]])) & @ X[Y[1, 2, 3]] (*-> Y[X[1, 2, 3]] *) 

EDIT: This should now also work if X has additional arguments besides Y:

(#[[1, 0]][#[[0]][Sequence @@ #[[1]]], Sequence @@ #[[2 ;;]]]) & @ X[Y[1,2,3],4,5] (*-> Y[X[1,2,3],4,5] *) 

Sequence@@ is necessary to get rid of the original head of 1,2,3 and 4,5, since Part always wraps such element sequences in the original head.

$\endgroup$
4
$\begingroup$

this is craziness... EventHorizon511's approach (through Part), but swap as many heads you want

HeadsReverse[expr_, n_] := Fold[#2 @ #1 &, #1[[1]] @@ expr[[Sequence @@ ConstantArray[1, n - 1], ;;]], #1[[2 ;;]] ] & @ Cases[expr, _, n, n, Heads -> True] HeadsReverse[X[Y[a, b, c]], 2] (* Y[X[a, b, c]] *) Table[HeadsReverse[1[2[3[u[v[x, y, z], f]]]], n], {n, 5}] (* { 1[2[3[u[v[x, y, z], f]]]], 2[1[3[u[v[x, y, z], f]]]], 3[2[1[u[v[x, y, z], f]]]], u[3[2[1[v[x, y, z], f]]]], v[u[3[2[1[x, y, z]]]]] } *) 

still not pure craziness, because when n == 5 f in the above example is gone

$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.