定義一個宏,產生一個接受參數的宏

定義一個宏,產生一個接受參數的宏

我已經使用乳膠有一段時間了,但僅限於最基本的。我盡可能地嘗試使用包。我現在正在嘗試自己編寫一些程式碼,以使我的乳膠文件更乾淨。這就是我想要實現的目標:

當我定義:

\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 的解決方案不同:您不需要expl3 cmplicated 宏,僅使用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}

相關內容