Create macro with variable number of comma separated arguments in plain TeX

comma-separated listmacrosplain-tex

I wish to create two macros: one that takes a known number, and another that takes an unknown number of arguments that are comma-separated and does something with them. There have been a few answers to this question before see (here and here), but they always use modern LaTeX packages such as xparse. For example, I could create a new fraction command (known number of args) by doing

\ExplSyntaxOn
\makeatletter
    \def\numargs{2}
    \NewDocumentCommand{\frc}{>{\SplitArgument{\numargs-1}{,}}m}{\@frc@#1}
    \NewDocumentCommand{\@frc@}{mm}{\frac{#1}{#2}}
\makeatother
\ExplSyntaxOff

and using it with \frc{1,2}, effectively doing the same as \frac{1}{2}. Another example would be to create a bolded list (unknown number of args) with

\ExplSyntaxOn
\NewDocumentCommand{\bflist}{m}{\clist_map_inline:nn{#1}{\@bflist@{##1}}}
\newcommand{\@bflist@}[1]{\bf #1}
\ExplSyntaxOff

and using it with \bflist{a, b, c, d, e, f}, etc, which would create the bolded list a b c d e f. Both of these solutions use modern LaTeX tools; I am wondering, is there a way to create these commands in plain TeX? Or at the very least, in LaTeX without using external packages?

Best Answer

The solution in very simple in Plain TeX (or more precisely: using only TeX primitive commands)

% fixed number of args:
\def\frc#1{\frcA#1\end}
\def\frcA#1,#2\end{{#1\over #2}}

test: $\frc{a,b}$

% unknown number of args:
\def\boldlist#1{\boldlistA #1,\end,}
\def\boldlistA #1#2,{%
   \ifx\end#1\else {\bf#1#2}\expandafter \boldlistA\fi
}

test: \boldlist{a, b, c, d, e, f}

\bye

Note that \boldlistA uses first unseparated parameter #1 followed by second separated #2 in order to remove spaces after commas. We need not to do it in the \frc macro because it is intended for math mode where spaces are ignored by TeX.

Second example in more detail: Assume syntax: \boldlist{a,b,cxy,d} without spaces after commas. Then we can define:

\def\boldlist#1{\boldlistA #1,\end,}
\def\boldlistA #1,{%
   \ifx\end#1\else {\bf#1}\expandafter \boldlistA\fi
}

This is recursive call of \boldlistA. The parameter #1 is a in first call (because it is separated by comma), then it is b, then cxy, then d and finally, it is \end. The test \ifx\end#1 stops this recursion.

If you want to use optional spaces before parameters (after comma) but you want to ignore them, i.e. \boldlist{a, b, cxy,d} then the \boldlistA have #1 unseparated: the #1 is first non-space token, spaces are ignored by TeX. The #2 is separated by comma. It is empty in the first case: #1=a, #2=empty, it is empty in second case #1=b, space before it is ignored, #2=empty, but it is not empty in third case: #1=c, space before it is ignored, #2=xy.