How to make a pipe-divided tuple?
I don't think you need a loop:
\documentclass{article}
\begingroup
\lccode`\~=`\|
\lowercase{\endgroup
\def\tup#1{{\def~{\;\middle\vert\;}\mathcode`\|="8000\left\langle#1\right\rangle}}}
\begin{document}
\[
\tup{a | b | c | z} + \tup{a |\frac{A}{B} | c | z}
\]
\end{document}
As a general rule, I recommend to avoid \left
and \right
whenever possible.
Here's an implementation with a syntax similar to commands defined with \DeclarePairedDelimiter
from mathtools
.
The unadorned command uses normal size; in the optional argument \big
, \Big
, \bigg
or \Bigg
can appear. The *
means using automatic sizing.
Spaces in the mandatory argument are ignored, so \tup{a|b|c}
is the same as \tup{a | b | c}
.
\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\tup}{som}
{
\IfBooleanTF{#1}
{
\tl_set:Nn \l__reinking_tup_open_tl { \left\langle }
\tl_set:Nn \l__reinking_tup_middle_tl { \;\middle|\; }
\tl_set:Nn \l__reinking_tup_close_tl { \right\rangle }
}
{
\IfNoValueTF{#2}
{
\tl_set:Nn \l__reinking_tup_open_tl { \langle }
\tl_set:Nn \l__reinking_tup_middle_tl { \mathrel{|} }
\tl_set:Nn \l__reinking_tup_close_tl { \rangle }
}
{
\tl_set:Nn \l__reinking_tup_open_tl { \mathopen{#2\langle} }
\tl_set:Nn \l__reinking_tup_middle_tl { \mathrel{#2|} }
\tl_set:Nn \l__reinking_tup_close_tl { \mathclose{#2\rangle} }
}
}
\__reinking_tup:n { #3 }
}
\tl_new:N \l__reinking_tup_open_tl
\tl_new:N \l__reinking_tup_middle_tl
\tl_new:N \l__reinking_tup_close_tl
\seq_new:N \l__reinking_tup_items_seq
\cs_new_protected:Nn \__reinking_tup:n
{
\seq_set_split:Nnn \l__reinking_tup_items_seq { | } { #1 }
\l__reinking_tup_open_tl
\seq_use:NV \l__reinking_tup_items_seq \l__reinking_tup_middle_tl
\l__reinking_tup_close_tl
}
\cs_generate_variant:Nn \seq_use:Nn { NV }
\ExplSyntaxOff
\begin{document}
$\tup{a|b|\dots|z}$
\quad
$\tup[\big]{a|b|\dots|z}$
\quad
$\tup[\Big]{a|b|\dots|z}$
\quad
$\tup*{\dfrac{a}{2}|b|\dots|z}$
\end{document}
A package-free version, which indiscriminately uses \left
, \middle
and \right
. The items are absorbed one at a time and appended to a list, then the list is executed.
\documentclass{article}
\usepackage{amsmath}
\makeatletter
\newcommand{\tup}[1]{%
\def\@tup@list{}%
\@tup#1|\@tup|
}
\def\@tup#1|{%
\ifx\@tup#1\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\left\langle\@tup@list\right\rangle}%
{\ifx\@tup@list\@empty\@tup@append{#1}\else\@tup@append{\;\middle|\;#1}\fi\@tup}%
}
\def\@tup@append#1{%
\expandafter\def\expandafter\@tup@list\expandafter{\@tup@list#1}%
}
\makeatother
\begin{document}
$\tup{a}$
$\tup{a|b|\dots|z}$
\end{document}
This way there's no problem with groups implicitly formed by \left
, \middle
and \right
.
Your command was almost working. If you put more items in \tup
, like $\tup{a|b|c|d|e|f}$
you'd see this:
it's not the first item which is left out, rather they are grouped in pairs. Your command starts with a \left\langle
, which starts a "math left group" and with the \@tempswa
switch set to false. In the first iteration of \@tuploop
you do \if@tempswa\@sep\else\@tempswatrue\fi
which expands to \@tempswatrue
, meaning that no \@sep
is inserted now, and \@tempswa
is now true. The command then inserts the first item (a
) and proceeds to the next iteration.
On the second iteration, \@tempswa
is true and \if@tempswa\@sep\else\@tempswatrue\fi
expands to \@sep
, which inserts a \middle|
(the separator after a
). The \middle
primitive will end the "math left group" started by \left\langle
and will start another "math left group". However, when the first group ended, your \@tempswa
switch was restored to its value outside the current group, which is false! And now the command inserts b
and goes to the third iteration, but now with \@tempswa
set to false once again.
So your command was actually inserting <token>|<token>
and then <token>|<token>
, and so on, due to the end of group triggered by \middle
. You could circumvent this with some \aftergroup
magic, or simply making a gloabl assignment to the switch:
\if@tempswa\@sep\else\global\@tempswatrue\fi
However, as egreg said in the comment, \@tempswa
is supposed to be set locally only, so it would be better if you created a \newif\ifg@insertsep
and then always used \global\g@insertseptrue
and \global\g@insertsepfalse
.
And since meanwhile egreg posted a much more elaborate expl3
answer than the one-liner I would post, I'll stop here ;-)