可变宏的问题

可变宏的问题

我正在使用以下生成器来生成可变宏:

% USAGE :: \VARIADIC{name}{start}{mid}{stop}
%
\newcommand{\VARIADIC}[4]{%
  \expandafter\newcommand\csname GobbleNext#1Arg\endcsname[1]{%
    #3##1\csname CheckNext#1Arg\endcsname%
  }%
  \expandafter\newcommand\csname CheckNext#1Arg\endcsname{%
    \csname @ifnextchar\endcsname\bgroup{\csname GobbleNext#1Arg\endcsname}{#4\endgroup}%
  }%
  \expandafter\newcommand\csname #1\endcsname[2]{%
    \begingroup#2##1#3##2\csname CheckNext#1Arg\endcsname%
  }%
}

本质上,它检查是否有更多的“参数”——以\bgroupie开头的标记\{,然后决定是否递归扩展或停止。

我的使用方法如下:

\VARIADIC {List} {[} {;} {]}
\VARIADIC {Sum} {(} {+} {)}

...

\begin{document}
  \List {a} {b} {c} {d} {e}
  \Sum {x} {y} {z}
\end{document}

我还可以应用简单的样式,例如:

\VARIADIC {Sum} {\textbf\bgroup(} {+} {)\egroup}

但我不确定这是否是最佳/正确的方法。我用了\ensuremath很多,但下面的宏不起作用——我不知道为什么……

\VARIADIC {Tuple} {\ensuremath\bgroup\langle} {,} {\rangle\egroup}

我希望能够\VARIADIC轻松地使用现有宏编写宏。具体来说,我正在寻找一种方法来编写任意现有的一元宏,如下所示\XYZ

\VARIADIC {Test} {\XYZ\bgroup(} {,} {)\egroup}

答案1

您的定义存在问题,因为某些宏要求其参数位于显式括号中。在您的\Tuple示例中,\ensuremath将读取以下参数\bgroup并确保此参数在数学模式下设置。但这不是您想要的。(我认为该\textbf示例也恰好因为此宏的定义方式而起作用。)

解决方案是,您可以\VARIADIC通过一个新参数扩展宏#2,然后将新定义的命令以 的形式包装到输出流中的所有材料。由于将开括号和闭括号拆分到不同的宏中非常棘手,因此我们不直接输出宏的材料,而是将其收集在另一个由和#2{...}传递的参数中。最后,当未找到新参数时,所有收集的材料都用 进行排版。\GobbleNext...Arg\CheckNext...Arg#2

如果您不想修改最终组,您可以将(新的)第二个参数留空。为组插入的显式括号将替换\begingroup ... \endgroup旧定义的括号。

\documentclass{article}

\newcommand{\VARIADIC}[5]{%
  \expandafter\newcommand\csname GobbleNext#1Arg\endcsname[2]{%
    \csname CheckNext#1Arg\endcsname{##1#4##2}%
    % Material moved to new argument ^^^^^^^^
  }%
  \expandafter\newcommand\csname CheckNext#1Arg\endcsname[1]{%
    \csname @ifnextchar\endcsname\bgroup{\csname GobbleNext#1Arg\endcsname{##1}}{#2{##1#5}}%
    % Wrapper macro #2 with new explicit braces ---------------------------------^-^-----^
  }%
  \expandafter\newcommand\csname #1\endcsname[2]{%
    \csname CheckNext#1Arg\endcsname{#3##1#4##2}%
    % Material moved to new argument ^^^^^^^^^^
  }%
}

\VARIADIC {List} {} {[} {;} {]}
\VARIADIC {Sum} {\textbf} {(} {+} {)}
\VARIADIC {Tuple} {\ensuremath} {\langle} {,} {\rangle}

\begin{document}
  \List {a} {b} {c} {d} {e}

  \Sum {x} {y} {z}

  \Tuple {\alpha} {\beta} {\gamma}
\end{document}

输出

在此处输入图片描述

答案2

不应使用具有可变参数数量的宏。您可以改为传递逗号分隔的列表,这更容易输入。

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\variadic}{mm}
 {
  \group_begin:
  \keys_set:nn { saswat/variadic } { #2 }
  \saswat_variadic_define:nVVVV { #1 }
   \l__saswat_variadic_env_tl % optional envelope
   \l__saswat_variadic_start_tl % start
   \l__saswat_variadic_mid_tl % mid
   \l__saswat_variadic_stop_tl % stop
  \group_end:
 }

\keys_define:nn { saswat/variadic }
 {
  env   .tl_set:N  = \l__saswat_variadic_env_tl,
  start .tl_set:N  = \l__saswat_variadic_start_tl,
  mid   .tl_set:N  = \l__saswat_variadic_mid_tl,
  stop  .tl_set:N  = \l__saswat_variadic_stop_tl,
  env   .initial:n = \use:n,
 }

\seq_new:N \l__saswat_variadic_items_seq

\cs_new_protected:Nn \saswat_variadic_define:nnnnn
 {
  \cs_new_protected:cpn { #1 } ##1
   {
    \seq_set_split:Nnn \l__saswat_variadic_items_seq { , } { ##1 }
    #2 { #3 \seq_use:Nn \l__saswat_variadic_items_seq { #4 } #5 }
   }
 }
\cs_generate_variant:Nn \saswat_variadic_define:nnnnn { nVVVV }

\ExplSyntaxOff

\variadic{List}{
  start=[,
  mid=;,
  stop=],
}

\variadic{Sum}{
  env=\textbf,
  start=(,
  mid=+,
  stop=),
}

\variadic{Tuple}{
  env=\ensuremath,
  start=\langle,
  mid={,},
  stop=\rangle,
}

\begin{document}

\List{a,b,c,d,e}

\Sum{x,y,z}

\Tuple{a,b,\dots,z}

\end{document}

我选择了键值接口,因此不需要记住参数的精确顺序,因为键可以按任何顺序指定。

关键env在于“封装宏”,请参阅示例。如果没有指定,则默认为\use:n本质上无操作,因为它仅传递其参数。

在此处输入图片描述

相关内容