Passing an argument with the alignment operator (&) to a macro within another aligned environment
You can do it, but I strongly recommend you not doing it. You gain nothing in using [
and ]
as delimiters for a mandatory argument.
\documentclass{article}
\usepackage{amsmath}
\makeatletter
\newcommand\bmat{{\ifnum\z@=`}\fi\@bmat}
\def\@bmat[#1]{\begin{bmatrix}#1\end{bmatrix}\ifnum\z@=`{\fi}}
\makeatother
\begin{document}
$\bmat[1&0\\0&1]$
\begin{align}
M &= \bmat[1&0\\0&1]
\end{align}
\end{document}
(Note: I have reduced the text width to shorten the output.)
When you understand the trick, you are allowed to use it. :) Hint: look for \eegroup
in Appendix D of the TeXbook.
Defining \mat
to look for the next token in order to decide a delimiter is, in my opinion, wrong. I'd do like this:
\newcommand{\mat}[2][]{\begin{#1matrix}#2\end{#1matrix}}
so that
\mat{1&2\\3&4} % no fences
\mat[b]{1&2\\3&4} % brackets
\mat[p]{1&2\\3&4} % parentheses
\mat[v]{1&2\\3&4} % vertical lines
\mat[V]{1&2\\3&4} % double vertical lines
\mat[B]{1&2\\3&4} % braces
would do even better, with minimum hassle and better readability.
Personally, I would stick with the long form, but it's a matter of taste.
Why this happens is rather interesting, since of course the raw code
\begin{align}
M = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}
\end{align}
does work even though the array separators are not between braces. The reason is that bmatrix
itself inserts braces specifically to make this work, and by the time scanning has reached the separators, TeX has already read the opening brace and knows that it should protect them.
In your code, it would seem that \bmat
is replaced with its expansion, which is the above code, before the &
is read, but in fact, the &
has already been read at that point: it needs to be picked up by the macro argument grabber. That is to say, even though the &
wasn't "executed" it was seen, and apparently, TeX will detect the end of an array cell even just when going through tokenization.
Because of this, there is no way to use the normal \newcommand\bmat[1][]{}
syntax to define a command that "just works" in arrays; egreg's answer shows how you can roll your own that accepts the same syntax but sneakily inserts braces. It's probably also possible to make a \catcode
change prior to scanning for the argument that would make []
into functional brace characters, but for all that effort, I suggest you redesign your macro not to use an optional argument instead. As a perhaps compromise, you can place braces around it: {\bmat[1&0\\0&1]}
, as Scott H. suggested.