Understanding a \@for loop

I'm having trouble with a \@for loop. I've got a macro that takes a comma delimited list and puts each element into a row of an array. When I do this using a \@for loop, I get an extra row that I don't understand. I can manually get rid of it with a negative space, (as in the commented line below) but that can't be the right way to do it, so I must be doing something wrong. Here's a minimal example. For comparison, if I construct what I expect the result of the loop to be manually, the extra row doesn't appear.

\documentclass{article}
\usepackage{amsmath}
\makeatletter
\newcommand{\fbun}[1]
{\ensuremath{\left[\begin{array}{c}
\@for\xx:=#1\do {\text{\xx}\\}
%     \\ [-2.75ex] % why is this required?
\end{array}\right]}}
\makeatother
\begin{document}
$\left[\begin{array}{c} A\\ B\\ C\\ D\\ \end{array}\right]$
% same array, but generated by a macro
\fbun{A,B,C,D}
\end{document}


-

As Altermundus said, you cannot add extra {} or \relax or other invisible material after the last row of the tabular. However, there is some extra material added after \@for. The implementation of \@for is not very good for this.

Since the \@for in LaTeX2e kernel has restrictions, I suggest \forcsvlist from etoolbox:

\documentclass{article}
\usepackage{amsmath}
\usepackage{etoolbox}
\newcommand{\fbun}[1]
{\ensuremath{\left[\begin{array}{c}
\end{array}\right]}}

\begin{document}
$\left[\begin{array}{c} A\\ B\\ C\\ D\\ \end{array}\right]$

\fbun{A,B,C,D}
\end{document}

-

In "User's Guide and Reference Manual" Leslie Lamport writes page 45:

There must be no &after the last item in a row and no \\ after the last row.

$\left[\begin{array}{c} A\\ B\\ C\\ D\\{}% \end{array}\right]$


This code gives a new line with an empty group. Each cell of an array is in a group.

\@foris a no developable loopso you need to write something like

\fbun{A,B,C}
D


or you can create a developable loop but it's more complicated :

\makeatletter
\newcommand*{\For}[1]{\noalign{\gdef\@Do##1{#1}}\@For}
\newcommand*{\@For}[3]{%
\unless\ifnum#1 \ifnum#3>0 >\else <\fi #2
\@Do{#1}%
\expandafter\@For\expandafter{\number\numexpr#1+#3}{#2}{#3}%
\fi
}
\makeatother

$\left[\begin{array}{c} \For{\@Alph{#1}\\}{1}{4}{1} \end{array}\right]$


\For is a developable loop for example, you can try :

\begin{tabular}{ll}
\For{A number & #1\\}{1}{20}{1}
\end{tabular}

-

The problem is that TeX finds something following the last \\ which starts a new row (it's neither \noalign nor \crcr that wouldn't).

A solution might be to use a token register: we develop the loop while in the first cell, so there's no problem of \xx not being defined any more after TeX has seen \\ (or &).

\usepackage{amsmath}
\makeatletter
\newcommand{\fbun}[1]{%
\begin{bmatrix}
\toks@={\@gobble}%
\@for\next:=#1\do
{\toks@=\@xp{\the\@xp\toks@\@xp\\\@xp\text\@xp{\next}}}%
\the\toks@
\end{bmatrix}}
\makeatother


I've used \@xp (from amsmath) that's a shorthand for \expandafter; if the \text around the entry wasn't required, then

\toks@=\expandafter{\the\expandafter\toks@\next}


would have sufficed. Initializing \toks@ to \@gobble has the effect that the first \\ is swallowed.

Instead of array I've used bmatrix (change it if you like) and, of course, I deleted \ensuremath as the first step. :)

-

I believe the reason you're getting a fifth, empty row when generating the column vector via the for-loop is that the fourth element (like the three before it) gets a \\ affixed to it; this instruction creates a new row which ends up being blank since there's no further content to create.

A (not very elegant) solution would be to redefine \fbun to take two arguments, as follows:

\newcommand{\fbun}[2]
{\ensuremath{\left[\begin{array}{c}
\@for\xx:=#1\do {\text{\xx}\\} #2
\end{array}\right]}}


and to invoke it as

\fbun{A,B,C}{D}

-
Thanks for your answer. I also thought that the final \\ was causing the problem, but I don't understand why the manually created version of the array, which also has the extra \\ doesn't have a fifth row. (As for your workaround, I think I prefer mine. :-)) –  Alan Munn Nov 16 '11 at 2:54
I had a look at the definition of the \@for command in the LaTeX kernel (file latex.ltx, beginning on row 859) to see if I could figure out why the loop form creates an extra row whereas the non-loop form does not. However, I must say I can't penetrate the dense, uncommented code in that file. :-( –  Mico Nov 16 '11 at 3:41
I seem to recall having looked at that code too. :-) Some more puzzles: if the extra row comes from the final \\, why isn't there a blank row between the C and D in your version of the command? Also, if you add an extra \\ after #2 in your command, you don't get an extra row. –  Alan Munn Nov 16 '11 at 3:42
Your first question: Well, there's a \\  after C, then a D is inserted as #2, so I don't see why there should be an empty row. (Incidentally, I did try out my code before posting the answer, to be sure there was no longer an extra row...) Re question 2: I can't tell for sure, but presumably it's for the same (and currently unknown/not-yet-understood) reason for why there's no blank row in the non-loop creation of the column vector... –  Mico Nov 16 '11 at 3:50
Right, but by hypothesis, the loop always should introduce an extra row at the end of the loop, so it's not clear to me why you shouldn't get two \\'s after the C, since you seem to get two \\'s after my version of the loop. That's what's so weird about the problem. (BTW, if you try to make the \\'s code the markup gets confused.) –  Alan Munn Nov 16 '11 at 3:59