我想创建一个宏,它接受两个参数,第二个参数是一个逗号分隔的列表,然后使用参数 2 的每个条目生成参数 1 的嵌套交换器。我一直试图通过循环遍历参数 2 中的值并递归调用一个简单的交换器宏来实现这一点,但我一直收到以下错误:
! TeX capacity exceeded, sorry [grouping levels=255].
我尝试使用etoolbox
,docsvlist
但不知道如何让它做我想做的事情。
看起来好像我遇到了无限循环,或者我的 def 方案存在一些问题,但我不知道它是什么。
详细信息:
基本换向器宏:
\newcommand{\commut}[2]{\left[{#1},{#2}\right]}
强力嵌套交换器:
\newcommand{\qcommut}[5]{\commut{\commut{\commut{\commut{#1}{#2}}{#3}}{#4}}{#5}}
尝试自动化版本:
\makeatletter
\newcommand{\ncommut}[2]{
\def\mainArg{#1}
\newcommand{\argList}{#2}
\@for\i:=\argList\do{
\def\mainArg{
\commut{\mainArg}{\i}
}
}
}
\makeatother
我可以调用\commut
和\qcommut
,但\ncommut
会产生错误。
\begin{equation}
\commut{A}{B}
\qcommut{A}{B}{C}{D}{E}
\ncommut{A}{B,C,D,E} % desired usage
\end{equation}
期望输出:
答案1
这是一个不同的 LaTeX3 实现,它也允许嵌套调用:
\documentclass{article}
\usepackage{xparse,mleftright}
\ExplSyntaxOn
\NewDocumentCommand{\commut}{ m }
{
\group_begin: \mactay_commut:n { #1 } \group_end:
}
\cs_new_protected:Npn \mactay_commut:n #1
{
\seq_set_from_clist:Nn \l__mactay_list_seq { #1 }
\int_compare:nTF { \seq_count:N \l__mactay_list_seq = 1 }
{ #1 } % only one element
{ % more than one element
% detach the first element
\seq_pop_left:NN \l__mactay_list_seq \l__mactay_first_tl
% add as many \mleft[ as needed
\prg_replicate:nn { \seq_count:N \l__mactay_list_seq }
{ \mleft[ }
% put the first element and a comma
\tl_use:N \l__mactay_first_tl ,
% deliver all the other elements, followed by \mright] and a comma
\seq_use:Nnnn \l__mactay_list_seq { \mright] , } { \mright] , } { \mright] , }
% final \mright]
\mright]
}
}
\seq_new:N \l__mactay_list_seq
\tl_new:N \l__mactay_first_tl
\ExplSyntaxOff
\begin{document}
$\commut{A}$
$\commut{A,B}$
$\commut{A,B,C}$
$\commut{A,B,C,D}$
$\commut{\commut{A,B},\commut{C,D}}$
\end{document}
答案2
\documentclass{article}
\newcommand{\commut}[2]{\left[{#1},{#2}\right]}
\makeatletter
\def\qcommut#1{\xcommut#1,\relax,}
\def\xcommut#1,{\xxcommut{#1}}
\def\xxcommut#1#2,{%
\ifx\relax#2%
#1%
\expandafter\@gobbletwo
\fi
\xxcommut{\commut{#1}{#2}}}
\begin{document}
$\qcommut{1,2,3,4,5,6}$
\end{document}
答案3
还有一个用于kvsetkeys
解析逗号分隔列表的解决方案。\qcommut
定义包含未扩展参数的\commut@list
嵌套调用:\commut
\documentclass{article}
\usepackage{kvsetkeys}
\usepackage{etexcmds}
\makeatletter
\newcommand*{\commut}[2]{\left[{#1},{#2}\right]}
\newcommand*{\qcommut}[1]{%
\let\commut@list\relax
\comma@parse{#1}\@qcommut
\typeout{\meaning\commut@list}% for debugging
\commut@list
}
\def\@qcommut#1{%
\ifx\commut@list\relax
\def\commut@list{#1}%
\else
\edef\commut@list{%
\noexpand\commut{%
\etex@unexpanded\expandafter{\commut@list}%
}{#1}%
}%
\fi
}
\makeatother
\begin{document}
\[ \qcommut{A,B,C,D,E} \]
\end{document}
宏\comma@list
:
macro:->\commut {\commut {\commut {\commut {A}{B}}{C}}{D}}{E}
答案4
这是一个快速的expl3
解决方案(前提是我理解正确)。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand {\ncommut} { m m }
{
\n_commut:nn {#1}{#2}
}
\cs_new:Npn \n_commut:nn #1#2
{
\tl_set:Nn \l_tmpa_tl {#1}
\clist_map_inline:nn {#2}
{
\tl_set:Nx \l_tmpa_tl {\__n_commut_aux:Vn \l_tmpa_tl {##1}}
}
\tl_use:N \l_tmpa_tl
}
\cs_new:Npn \__n_commut_aux:Vn #1#2
{
\left[{#1},{#2}\right]
}
\ExplSyntaxOff
\begin{document}
$\ncommut{1}{2,3,4,5}$
$\ncommut{a}{b,c,d,e,f,g}$
\end{document}