定义一个宏,该宏生成一个接受参数的宏

定义一个宏,该宏生成一个接受参数的宏

我已经使用 latex 有一段时间了,但仅限于最基本的功能。我尽可能使用软件包。我现在正在尝试自己编写一些代码,以使我的 latex 文档更简洁。这就是我想要实现的目标:

当我定义:

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

我希望能够使用

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

请注意,索引的数量不一定是 2,可以是 1,也可以大于 2。

以下是我现在所拥有的:

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

基本上,我希望能够使用它\symb{flow}{f_#1^#2}[a,b]来定义一个接受可选参数的宏\flow,该参数是变量的逗号分隔索引。如果没有提供可选参数,则将使用默认索引(在本例中为 a、b)。

在 Python 中,可以写成:

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$

答案1

你可以这样做,但你不应该将 Python 作为 LaTeX 编程的模型。

在 LaTeX 中,参数是用括号括起来的,不能用逗号列表代替。

无论如何,这里有一个在模板中有任意数量参数的实现(但你当然必须指定你想要多少个)。

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

在此处输入图片描述

关于代码还有更多话要说。首先是简单的事情:

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

expl3版本

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

并且应被优先考虑。

接下来介绍其\symb工作原理。首先,它定义一个内部函数,其参数数量与声明的一样多;其替换文本由给定的模板提供。因此\symb{flow}{2}{f_{#1}^{#2}}{a,b}定义

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

_注意。是 范围内的字母这一事实没有问题,因为给出了\ExplSyntaxOn声明\symb{flow}{2}{...}{...}外部那个范围。

之后我们定义一个用户级命令\flow,该命令带有一个可选参数,其默认值是 的第四个参数\symb。该命令通过 间接调用了前面定义的函数\__kelvin_symb_do:nnx

在本例中,第一个参数是 ,flow第二个参数是参数的数量;它们的目的是能够调用内部函数。最后一个参数是逗号列表(默认值或作为 的可选参数给出的列表\flow),但经过预处理,以便生成一个括号项列表。

正常版本\__kelvin_symb_do:nnn只是形成内部函数\kelvin_symb_flow:nn并取消第三个参数的括号。但我们使用的是其变体;当

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

完全展开(因为x变体),如果应用到a,b它会产生{a}{b}。因此我们最终得到

\kelvin_symb_flow:nn { a } { b }

并且 LaTeX 很高兴像往常一样扩展到f_{a}^{b}

答案2

例如,你可以使用这个:

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

该宏的第二个版本根据评论实现了您的要求:

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

这个解决方案与 egreg 的解决方案不同:您不需要解释复杂的宏,只需要使用 TeX 原语。

答案3

这与 wipet 类似,但强制要求 symb 参数,如评论中所述

在此处输入图片描述

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

还有一个版本允许参数列表中有多个(最多 8 个)条目。

在此处输入图片描述

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

相关内容