Defina uma macro que gere uma macro que receba argumentos

Defina uma macro que gere uma macro que receba argumentos

Já uso látex há algum tempo, mas limitado apenas ao básico. Tento usar pacotes sempre que possível. Agora estou tentando escrever alguns códigos sozinho, para deixar meu documento de látex mais limpo. Isto é o que eu quero alcançar:

Quando eu defino:

\symb{flow}{f_#1^#2}[a,b]

Eu quero poder usar

\flow        % outputs $f_a^b$
\flow[x,y]   % outputs $f_x^y$

Observe que o número de índices não deve ser necessariamente 2, pode ser 1 ou pode ser maior que 2.

O seguinte é o que tenho agora:

\NewDocumentCommand{\symb}{m m m}
{ \expandafter\NewDocumentCommand\csname#1\endcsname{>{\SplitList{,}}O{#3}}
    { 
        % Not sure what I need to write here
    }
}

Basicamente, quero poder usar \symb{flow}{f_#1^#2}[a,b]para definir uma macro \flowque receba um argumento opcional, que é um índice da variável delimitado por vírgula. Caso o argumento opcional não seja fornecido, serão utilizados os índices padrão (neste caso a, b).

Em python, isso seria escrito como:

def symb(expr, default):
    def fn(*args):
        if len(args) == 0:
            return expr % args
        else:
            return expr % default

    return fn

flow = symb('$f_%s^%s$', (a, b))

flow()        % outputs $f_a^b$
flow(x, y)    % outputs $f_x^y$

Responder1

Você pode fazer isso, mas não deve tomar o Python como modelo para programação em LaTeX.

No LaTeX, os argumentos são entre colchetes e não podem ser substituídos por listas de vírgulas.

De qualquer forma, aqui está uma implementação com qualquer número de argumentos no modelo (mas é claro que você deve especificar quantos deseja).

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

insira a descrição da imagem aqui

Mais algumas palavras sobre o código. Primeiro as coisas fáceis:

\exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }

é a expl3versão de

\expandafter\NewDocumentCommand\csname#1\endcsname { O{#4 } }

e deve ser preferido.

A seguir uma descrição de como \symbfunciona. Primeiro ele define uma função interna com tantos argumentos quantos forem declarados; seu texto de substituição é fornecido pelo modelo fornecido. Assim \symb{flow}{2}{f_{#1}^{#2}}{a,b}define

\kelvin_symb_flow:nn { f_{#1}^{#2} }

Observação. Não há problema com o fato de _ser uma carta no escopo de \ExplSyntaxOn, pois a declaração \symb{flow}{2}{...}{...}é dadaforaesse escopo.

Depois disso, definimos o comando de nível de usuário \flowcom um argumento opcional, cujo padrão é o quarto argumento para \symb. Este comando chama indiretamente a função definida anteriormente por meio de \__kelvin_symb_do:nnx.

O primeiro argumento será, neste caso, flowo segundo é o número de argumentos; seu objetivo é poder chamar a função interna. O último argumento é a lista de vírgulas (o padrão ou aquele fornecido como argumento opcional para \flow), mas pré-processado para produzir uma lista de itens entre colchetes.

A versão normal \__kelvin_symb_do:nnnapenas forma a função interna \kelvin_symb_flow:nne desamarra o terceiro argumento. Mas estamos usando uma variante disso; quando

\clist_map_function:nN { #1 } \__kelvin_symb_brace:n

é totalmente expandido (por causa da xvariante), se aplicado a a,bele produz {a}{b}. Assim acabamos com

\kelvin_symb_flow:nn { a } { b }

e o LaTeX está feliz em expandir como de costume para f_{a}^{b}.

Responder2

Por exemplo, você pode usar isto:

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

A segunda versão desta macro implementa seus requisitos a partir dos comentários:

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

Esta solução difere da solução do egreg: você não precisa de macros complicadas explicadas, apenas primitivas TeX são usadas.

Responder3

Isto é semelhante ao do limpet, mas torna o argumento do símbolo obrigatório, conforme discutido nos comentários

insira a descrição da imagem aqui

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

E uma versão que permite múltiplas (até 8) entradas na lista de argumentos.

insira a descrição da imagem aqui

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

informação relacionada