引数を受け取るマクロを生成するマクロを定義する

引数を受け取るマクロを生成するマクロを定義する

私はこれまでかなり長い間 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

可能ですが、LaTeX でのプログラミングのモデルとして Python を採用すべきではありません。

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オプションの引数を持つユーザー レベル コマンドを定義します。そのデフォルトは の 4 番目の引数です\symb。このコマンドは、 によって以前に定義された関数を間接的に呼び出します\__kelvin_symb_do:nnx

この場合、最初の引数は 、flow2 番目の引数は引数の数です。引数の目的は、内部関数を呼び出せるようにすることです。最後の引数はコンマ リスト (デフォルトまたは のオプション引数として指定されたもの\flow) ですが、前処理されて中括弧で囲まれた項目のリストが生成されます。

通常のバージョンでは、\__kelvin_symb_do:nnn内部関数を形成し\kelvin_symb_flow:nn、3番目の引数を括弧で囲まないだけです。しかし、私たちはそのバリエーションを使用しています。

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

このマクロの 2 番目のバージョンでは、コメントからの要件を実装します。

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

関連情報