Определите макрос, который генерирует макрос, принимающий аргументы.

Определите макрос, который генерирует макрос, принимающий аргументы.

Я уже довольно давно использую латекс, но ограничиваюсь только самыми основами. Я стараюсь использовать пакеты, когда это возможно. Сейчас я пытаюсь написать несколько кодов сам, чтобы сделать свой латексный документ чище. Вот чего я хочу добиться:

Когда я определяю:

\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 macros, используются только примитивы 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}

Связанный контент