Define a macro that generates a macro that takes in arguments
You can do it, but you should not take Python as a model for programming in LaTeX.
In LaTeX arguments are braced and cannot be substituted by comma lists.
Anyway, here's an implementation with any number of arguments in the template (but you of course have to specify how many you want).
\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\symb}{mmmm}
{% #1=name of command to define, #2=number of args, #3=template, #4=default
% define the internal version
\cs_new_protected:cn { kelvin_symb_#1:\prg_replicate:nn{#2}{n} } { #3 }
% define the external version
\exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }
{
\__kelvin_symb_do:nnx { #1 } { #2 } { \clist_map_function:nN { ##1 } \__kelvin_symb_brace:n }
}
}
\cs_new:Nn \__kelvin_symb_do:nnn
{
\use:c { kelvin_symb_#1:\prg_replicate:nn{#2}{n} } #3
}
\cs_generate_variant:Nn \__kelvin_symb_do:nnn { nnx }
\cs_new:Nn \__kelvin_symb_brace:n { {#1} }
\ExplSyntaxOff
\symb{flow}{2}{f_{#1}^{#2}}{a,b}
\symb{foo}{4}{\int_{#1}^{#2}#3\,d#4}{0,1,x,x}
\begin{document}
$\flow$
$\flow[x,y]$
$\foo$
$\foo[a,b,f(x),x]$
\end{document}
Some more words on the code. First the easy things:
\exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }
is the expl3
version of
\expandafter\NewDocumentCommand\csname#1\endcsname { O{#4 } }
and should be preferred.
Next a description of how \symb
works. First it defines an internal function with as many arguments as declared; its replacement text is provided by the given template. Thus \symb{flow}{2}{f_{#1}^{#2}}{a,b}
defines
\kelvin_symb_flow:nn { f_{#1}^{#2} }
Note. There is no problem with the fact that _
is a letter in the scope of \ExplSyntaxOn
, because the declaration \symb{flow}{2}{...}{...}
is given outside that scope.
After that we define the user level command \flow
with an optional argument, whose default is the fourth argument to \symb
. This command indirectly calls the previously defined function by means of \__kelvin_symb_do:nnx
.
The first argument will be, in this case, flow
, the second one is the number of arguments; their purpose is to be able to call the inner function. The last argument is the comma list (the default or the one given as optional argument to \flow
) but preprocessed so that it yields a list of braced items.
The normal version \__kelvin_symb_do:nnn
just forms the internal function \kelvin_symb_flow:nn
and unbraces the third argument. But we're using a variant thereof; when
\clist_map_function:nN { #1 } \__kelvin_symb_brace:n
is fully expanded (because of the x
variant), if applied to a,b
it yields {a}{b}
. Thus we end up with
\kelvin_symb_flow:nn { a } { b }
and LaTeX is happy to expand as usual to f_{a}^{b}
.
For example, you can use this:
\def\sdef#1{\expandafter\def\csname#1\endcsname}
\def\symb#1#2[#3,#4]{%
\sdef{#1}{\expandafter\futurelet\expandafter\next\csname#1:a\endcsname}%
\sdef{#1:a}{\ifx\next[\csname#1:b\expandafter\endcsname
\else \csname#1:b\endcsname[#3,#4]\fi}%
\sdef{#1:b}[##1,##2]{#2}%
}
\symb{flow}{f_#1^#2}[a,b]
$\flow$ and $\flow[x,y]$.
Second version of this macro implements your requirement from comments:
\def\sdef#1{\expandafter\def\csname#1\endcsname}
\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\symb#1#2[#3]{%
\sdef{#1}{\expandafter\futurelet\expandafter\next\csname#1:a\endcsname}%
\sdef{#1:a}{\ifx\next[\csname#1:b\expandafter\endcsname
\else \csname#1:c\endcsname #3,,,,,,,,\end \fi}%
\sdef{#1:b}[##1]{\def\paramslistA{#3,}\def\paramslistB{}\setparams ##1,\end,
\csname#1:c\expandafter\endcsname \paramslistB,,,,,,,,\end}%
\sdef{#1:c}##1,##2,##3,##4,##5,##6,##7,##8,##9\end{#2}%
}
\def\setparams #1,{\ifx\end#1%
\expandafter\addto\expandafter\paramslistB\expandafter{\paramslistA}%
\else \expandafter \setparamslist \paramslistA \end #1,%
\expandafter\setparams\fi}
\def\setparamslist#1,#2\end#3,{\def\paramslistA{#2}\addto\paramslistB{#3,}}
\symb{flow}{f_#1^#2}[a,b]
\symb{test}{test: 1=#1, 2=#2, 3=#3, 4=#4}[a,b,c,d]
$\flow$ and $\flow[x,y]$.
\test
\test[mmm]
\test[x,y,z]
This solution differs from egreg's solution: you need not expl3 cmplicated macros, only TeX primitives are used.
This is similar to wipet's but makes the argument to symb mandatory as discussed in comments
\documentclass{article}
\def\symb#1#2#3{%
\expandafter\def\csname x#1\endcsname##1##2{#2}%
\expandafter\newcommand\csname #1\endcsname[1][#3]{%
\expandafter\splitcomma\csname x#1\endcsname ##1\relax}}
\def\splitcomma#1#2,#3\relax{#1{#2}{#3}}
\begin{document}
\symb{flow}{f_#1^#2}{a,b}
$\flow$
$\flow[x,y]$
\end{document}
And a version that allows multiple (up to 8) entries in the argument list.
\documentclass{article}
\def\symb#1#2#3{%
\expandafter\def\csname x#1\endcsname##1##2##3##4##5##6##7##8##9{#2}%
\expandafter\newcommand\csname #1\endcsname[1][#3]{%
\expandafter\splitcomma\csname x#1\endcsname ##1,,,,,,,,,,\relax}}
\def\splitcomma#1#2,#3,#4,#5,#6,#7,#8,#9\relax{#1{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}\relax}
\begin{document}
\symb{flow}{f_#1^#2}{a,b}
\symb{flowb}{f_#1^#2g_#3^#4}{a,b,c,d}
$\flow$
$\flow[x,y]$
$\flowb$
$\flowb[x,y,w,z]$
\end{document}