11

I would like to make a macro that takes two arguments, the second of which is a comma separated list and then produces a nested commutator of argument1 with each entry of argument2. I've been attempting to do this by looping over the values in argument2 and recursively calling a simple commutator macro, but I keep getting the following error:

! TeX capacity exceeded, sorry [grouping levels=255].

I tried to use etoolbox's docsvlist, but couldn't figure out how to make it do what I wanted.

It seems like I have an infinite loop, or some problem with my def scheme, but I don't know what it is.

Details:
Basic commutator macro:

\newcommand{\commut}[2]{\left[{#1},{#2}\right]}

Brute force nested commutator:

\newcommand{\qcommut}[5]{\commut{\commut{\commut{\commut{#1}{#2}}{#3}}{#4}}{#5}}

Attempt at automated version:

\makeatletter
\newcommand{\ncommut}[2]{
  \def\mainArg{#1}
  \newcommand{\argList}{#2}
  \@for\i:=\argList\do{
    \def\mainArg{
      \commut{\mainArg}{\i}
    }
  }
}
\makeatother

I can call \commut and \qcommut, but \ncommut produces the error.

\begin{equation}
  \commut{A}{B}
  \qcommut{A}{B}{C}{D}{E}
  \ncommut{A}{B,C,D,E} % desired usage
\end{equation}

Desired output:

Desired Output

3
  • 1
    So could you include (for the sake of completeness), the expected output from using \commut{A}{B}, \qcommut{A}{B}{C}{D}{E} and (say) \ncommut{A}{B,C,D,E}?
    – Werner
    Commented Dec 4, 2012 at 20:40
  • You can't use \mainArg in the definition of \mainArg. You need to expand it first.
    – cgnieder
    Commented Dec 4, 2012 at 20:41
  • 1
    Note that all 3 answers (and latex syntax guidelines) have followed your question title and use comma separated list, but your example code used multiple {} groups (which has no obvious terminator for the list) Commented Dec 4, 2012 at 21:10

4 Answers 4

9

Here's a different LaTeX3 implementation that allows also for nested calls:

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

enter image description here

10

enter image description here

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

And a solution with kvsetkeys for parsing the comma separated list. \qcommut defines \commut@list containing the nested \commut calls with unexpanded arguments:

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

Macro \comma@list:

macro:->\commut {\commut {\commut {\commut {A}{B}}{C}}{D}}{E}

Result

4

Here's a quick expl3 solution (provided that I understand correctly).

enter image description here

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .