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

  • 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 Dec 4 '12 at 20:40
  • You can't use \mainArg in the definition of \mainArg. You need to expand it first. – clemens Dec 4 '12 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) – David Carlisle Dec 4 '12 at 21:10
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}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.