1

I've learnt from this post how to swap two commands using the let primitive:

\let\temp\first
\let\first\second
\let\second\temp
\let\temp\undefined

Now, in order not to flood my preamble with this pattern, and to ease maintenance of my document, I wish to loop over this to perform all my swaps at once, with something like:

\foreach \lhs/\rhs in {%
    phi/varphi,%    easier to..
    sim/thicksim,%  .. tweak and maintain ..
    % ...           .. with a long list of swaps
    } {%
       % .. what to input here?
       % \expandafter\let\csname\lhs\endcsname\csname\rhs\endcsname 
       % does not work, because \let seems confined inside the loop scope
    }

How do I perform all my swaps in a row like this?
Why is there not an \xlet like there is a \xdef?

iago-lito
  • 1,472

1 Answers1

1

This works by parsing a comma separated list of \first/\second macros using listofitems. For the particular example, \swap{\phi/\varphi,\alpha/\beta}, this puts \phi into \swaplist[1,1] (after expanding twice the latter macro), \varphi into \swaplist[1,2], \alpha into \swaplist[2,1] and \beta into \swaplist[2,2].

Now all that is required is a loop through the first index (performed with \foreachitem) to do what the OP showed at the top...a series of \global\lets. The particulars are a game of expansion, so that the \swaplist macros are twice expanded at the time of the \let.

\documentclass{article}
\usepackage{listofitems}
\def\swapA{\let\temp}
\newcommand\swap[1]{%
  \setsepchar[-]{,-/}%
  \readlist*\swaplist{#1}%
  \foreachitem\x\in\swaplist{%
    \expandafter\expandafter\expandafter\swapA\swaplist[\xcnt,1]%
    \edef\swapB{\noexpand\global\noexpand\let\swaplist[\xcnt,1]}%
    \expandafter\expandafter\expandafter\swapB\swaplist[\xcnt,2]%
    \edef\swapC{\noexpand\global\noexpand\let\swaplist[\xcnt,2]}%
    \expandafter\swapC\temp%
  }%
}
\begin{document}
\swap{\phi/\varphi,\alpha/\beta}
\noindent phi: $\phi$\\
 varphi: $\varphi$\\
 alpha: $\alpha$\\
 beta: $\beta$
\end{document}

enter image description here

If the alternate syntax is desired, that omits the backslashes, \swap{phi/varphi,alpha/beta}, then this would suffice, to accomplish the same task. Double expansion is no longer needed, since \csname will fully expand its \swaplist argument.

\documentclass{article}
\usepackage{listofitems}
\def\swapA{\let\temp}
\newcommand\swap[1]{%
  \setsepchar[-]{,-/}%
  \readlist*\swaplist{#1}%
  \foreachitem\x\in\swaplist{%
    \expandafter\swapA\csname\swaplist[\xcnt,1]\endcsname%
    \edef\swapB{\noexpand\global\noexpand\let\csname\swaplist[\xcnt,1]\endcsname}%
    \expandafter\swapB\csname\swaplist[\xcnt,2]\endcsname%
    \edef\swapC{\noexpand\global\noexpand\let\csname\swaplist[\xcnt,2]\endcsname}%
    \expandafter\swapC\temp%
  }%
}
\begin{document}
\swap{phi/varphi,alpha/beta}
\noindent phi: $\phi$\\
 varphi: $\varphi$\\
 alpha: $\alpha$\\
 beta: $\beta$
\end{document}
  • Wow. This seems to work indeed Ô.Ô What's the idea? Is the \foreach option a dead-end, and why? – iago-lito Apr 16 '18 at 12:01
  • @iago-lito I added some commentary. – Steven B. Segletes Apr 16 '18 at 12:06
  • Well, cheers :) I'll have a look into this listofitems package, which seems quite powerful. Anyway, it looks like LaTeX remains quite hard to read and write for humans, right? XD – iago-lito Apr 16 '18 at 12:09
  • @iago-lito I have added an alternate version, if you prefer the syntax without backslashes, \swap{phi/varphi,alpha/beta} – Steven B. Segletes Apr 16 '18 at 12:12
  • I don't mind. As long as it is easy to read and maintain :) But thanks! – iago-lito Apr 16 '18 at 12:14
  • 1
    @iago-lito The listofitems package is extremely powerful and handy for dissecting complex lists. Documentation here: https://ctan.org/pkg/listofitems, and also search for listofitems on this tex.stackexchange website for ways it can be used. – Steven B. Segletes Apr 16 '18 at 12:16