# \newcommand for bmatrix of features using pgffor throws missing \endgroup error

There are two parts to this question. Mainly, I'm interested in implementing a \newcommand that can take an arbitrary number of arguments to be set in a single column of a matrix.

I tried the following, but it throws a missing \endgroup error (and it seems to be a result of \\, because taking out \\ eliminates the error, but then the desired result is not achieved):

\documentclass{article}

\usepackage{pgffor}
\usepackage{amsmath}

\newcommand*{\Features}[1]{%
$$% \begin{bmatrix}% \foreach \entry in {#1} {\text{\entry}\\} \end{bmatrix}%$$%
}

\begin{document}

\Features{--ACC, +PL}

\end{document}


Is there an easy way to fix this to make it work as desired?

The second part of the question is why this is happening. I'm curious for the sake of learning and for the sake of being able to write better macros in the future, but I haven't been able to figure out what's causing the missing \endgroup error.

• The problem is always the same: \foreach executes each cycle in a group, so \\ is seen inside that group and the alignment process is messed up. – egreg Nov 22 '13 at 22:53
• @egreg, I'm not sure I am entirely following the explanation, but I take it to mean that there's no easy workaround with pgffor? If not, is there a better way to do this? – Adam Liter Nov 22 '13 at 23:00
• I came across A. Ellet's answer here, which I think is related, but I did not entirely understand what was going on in this answer. – Adam Liter Nov 22 '13 at 23:03

Enrico Gregorio has already explained the reason in his comment: \foreach puts the body of its loop in a group. That conflicts with the cell grouping of the matrix environment. Another problem, if there is something after the line end that is not expandable (end of group, \relax, ...), then a new (empty) line is created.

The following uses the loop to define \MatrixBody that contains the lines of the matrix. The chain of \expandafter expands \entry once. Otherwise the macro \MatrixBody would contain \entry in each matrix line, undefined after the loop.

Global assignments are only used because of \g@addto@macro from LaTeX's kernel that allows to add stuff to a macro. (Local variants are defined by packages, such as ltxcmds).

\documentclass{article}

\usepackage{pgffor}
\usepackage{amsmath}

\makeatletter
\newcommand*{\Features}[1]{%
\global\let\MatrixBody\@empty
\foreach \entry in {#1} {%
\expandafter{%
\expandafter\text\expandafter{\entry}\\%
}%
}%
$$% \begin{bmatrix}% \MatrixBody \end{bmatrix}%$$%
}
\makeatother

\begin{document}

\Features{--ACC, +PL}

\end{document}


The problem is that \foreach executes each cycle in a group. So in your case you're basically doing

$$\begin{bmatrix} \begingroup\text{--ACC}\\\endgroup \begingroup\text{+PL}\\\endgroup \end{bmatrix}$$


which indeed stops with

! Missing \endgroup inserted.
<inserted text>
\endgroup


You have to build the contents of the matrix beforehand. Also using a cycle process that doesn't group is a lost battle anyway, because also table cells are evaluated in a group and \\ ends it.

Here's an expl3 based macro.

\documentclass{article}

\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
% the user level command
\NewDocumentCommand{\Features}{ m }
{
}
% a variable
% the programmer level function
{
% clear the sequence
% do a mapping on the comma list separated input
% adding the item between \mathrm{ and }
\clist_map_inline:nn { #1 }
{
\seq_put_right:Nn \l_adam_items_seq { \mathrm { ##1 } }
}
$$\begin{bmatrix} % deliver the items separated by \\ \seq_use:Nn \l_adam_items_seq { \\ } \end{bmatrix}$$
}
\ExplSyntaxOff

\begin{document}

\Features{-ACC, +PL}

\end{document}


Note that I use \mathrm rather than \text; but it's personal choice.

• + 1 Thanks! The explanation of the problematic \foreach grouping is very clear, though I've gone ahead and accepted Heiko's answer, as I prefer a LaTeX2e solution, at least for the time being. I still haven't had time to try to learn any LaTeX3 syntax. :) – Adam Liter Nov 22 '13 at 23:21