The \addto macro appends code to another macro.
If you have \def\foo{X} and do \addto\foo{Y}, TeX will do
\expandafter\def\expandafter\foo\expandafter{\foo Y}
which results in
\def\foo{XY}
after the \expandafter chain has done its work. However, you can't use \addto if you plan to use the code in LaTeX, because \addto is an important command used by babel and you risk disaster if you redefine it. Just use another name.
What does \matr do? It does \def\matrL{}, which initializes a container for the body of the matrix. Next it passes the argument to \matrA, starting a recursion.
The macro \matrA just read the following tokens one by one:
- if the next token is
, (denoting end of a cell), then & is appended to \matrL;
- if the next token is
; (denoting end of a row), then \cr is appended to \matrL;
- if the next token is
\end, the endgame is run, namely \pmatrix{\matrL} is executed and the recursion stops;
- in all other cases, the token is just appended to
\matrL.
Can you adapt this to LaTeX and specifically to a pmatrix environment? Yes, easily.
First of all, choose different names for the internal macros, preferably with @ in them.
\documentclass{article}
\usepackage{amsmath}
\makeatletter
\newcommand{\matr}[1]{\def\tsskyx@matrL{}\tsskyx@matrA#1\end}
\def\tsskyx@addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\tsskyx@matrA#1{%
\ifx\end#1%
\begin{pmatrix}\tsskyx@matrL\end{pmatrix}%
\else
\ifx,#1%
\tsskyx@addto\tsskyx@matrL{&}%
\else
\ifx;#1%
\tsskyx@addto\tsskyx@matrL{\}%
\else
\tsskyx@addto\tsskyx@matrL{#1}%
\fi
\fi
\expandafter\tsskyx@matrA
\fi
}
\makeatother
\begin{document}
[
\matr{a,b;c,d}
]
\end{document}
The same code, with minimal differences: instead of \cr we append \\ and \begin{pmatrix}...\end{pmatrix} is used.
A different implementation using expl3, where an optional argument specifies the delimiters (default p, can be bvVB with amsmath conventions).
\documentclass{article}
\usepackage{amsmath}
\ExplSyntaxOn
\NewDocumentCommand{\matr}{O{p}m}
{
\tsskyx_matr:nn { #1 } { #2 }
}
\seq_new:N \l__tsskyx_matr_body_seq
\cs_new_protected:Nn \tsskyx_matr:nn
{
% build the matrix
\begin{#1matrix}
% split the argument at ;
\seq_set_split:Nnn \l__tsskyx_matr_body_seq { ; } { #2 }
% map the items, that are comma separated lists
\seq_map_function:NN \l__tsskyx_matr_body_seq __tsskyx_matr_row:N
\end{#1matrix}
}
\cs_new_protected:Nn __tsskyx_matr_row:N
{
\clist_use:nn { #1 } { & } \
}
\ExplSyntaxOff
\begin{document}
[
\matr{a,b;c,d}
\qquad
\matr[b]{a,b;c,d}
]
\end{document}

If you also want to change the row and column separator, you can use a key-value system.
\documentclass{article}
\usepackage{amsmath}
\ExplSyntaxOn
\NewDocumentCommand{\matr}{O{}m}
{
\group_begin:
\keys_set:nn { tsskyx/matr } { #1 }
\tsskyx_matr:n { #2 }
\group_end:
}
\seq_new:N \l__tsskyx_matr_body_seq
\seq_new:N \l__tsskyx_matr_row_seq
\keys_define:nn { tsskyx/matr }
{
row-sep .tl_set:N = \l__tsskyx_matr_rowsep_tl,
col-sep .tl_set:N = \l__tsskyx_matr_colsep_tl,
delim .tl_set:N = \l__tsskyx_matr_delim_tl,
row-sep .initial:n = { ; },
col-sep .initial:n = { , },
delim .initial:n = { p },
}
\cs_new_protected:Nn \tsskyx_matr:n
{
% build the matrix
\begin{\l__tsskyx_matr_delim_tl matrix}
% split the argument at ;
\seq_set_split:NVn \l__tsskyx_matr_body_seq \l__tsskyx_matr_rowsep_tl { #1 }
% map the items, that are comma separated lists
\seq_map_function:NN \l__tsskyx_matr_body_seq __tsskyx_matr_row:N
\end{\l__tsskyx_matr_delim_tl matrix}
}
\cs_new_protected:Nn __tsskyx_matr_row:N
{
\seq_set_split:NVn \l__tsskyx_matr_row_seq \l__tsskyx_matr_colsep_tl { #1 }
\seq_use:Nn \l__tsskyx_matr_row_seq { & } \
}
\ExplSyntaxOff
\begin{document}
\begin{gather}
\matr{a,b;c,d}
\
\matr[delim=b]{a,b;c,d}
\
\matr[row-sep=\,col-sep=&,delim=V]{a & b \ c & d}
\
\matr[row-sep=;,col-sep=:]{a:b;c:d}
\end{gather}
\end{document}

\addtois documented in OpTeX documentation. – wipet Jan 17 '24 at 11:09