
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 \flow
que 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}
Mais algumas palavras sobre o código. Primeiro as coisas fáceis:
\exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }
é a expl3
versão de
\expandafter\NewDocumentCommand\csname#1\endcsname { O{#4 } }
e deve ser preferido.
A seguir uma descrição de como \symb
funciona. 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 \flow
com 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, flow
o 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:nnn
apenas forma a função interna \kelvin_symb_flow:nn
e 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 x
variante), se aplicado a a,b
ele 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
\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.
\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}