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}

enter image description here

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

enter image description here

\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.

enter image description here

\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}

Tags:

Macros