9

Is it possible to have a macro like this one:

\documentclass{article}
\usepackage{xparse}
\pagestyle{empty}
\ExplSyntaxOn
\NewDocumentCommand{\HowManyArguments}{ oooooooo }
    {
        \IfNoValueTF {#1} { 0 }{
            \IfNoValueTF {#2} { 1 }{
                \IfNoValueTF {#3}  { 2 }{
                     \IfNoValueTF {#4}  { 3 }{
                          \IfNoValueTF {#5}  { 4 }{
                               \IfNoValueTF {#6}  { 5 }{
                                    \IfNoValueTF {#7}  { 6 }{
                                         \IfNoValueTF {#8}  { 7 }{ So many }
                                    }
                               }
                          }
                     }
                }
            }
        }
    }
\ExplSyntaxOff
\begin{document}

The amount of arguments in this macro is \HowManyArguments[Cake][Chair][Stool][Bicycle] .

\end{document}

Except one that doesn't have limitations, a bit like the \powertower thread, where the result is embedded in the rest every time: How do I typeset a tenfold powering (a tower-of-powers) with LaTeX?

The idea is then to use the first argument of the macro to define the number of arguments.

The reason why I need the "powertower" approach is because of part 2: I want to rotate between colours based on the number of the argument.

Try compiling this:

\documentclass{article}
\usepackage{xparse}
\usepackage{xcolor}
\pagestyle{empty}
\ExplSyntaxOn
\NewDocumentCommand{\HowManyArguments}{ oooooooo }
    {
        \IfNoValueTF {#1} {}{
            \IfNoValueTF {#2} {\textcolor{blue}{#1(}...\textcolor{blue}{)}}{
                \IfNoValueTF {#3}  {\textcolor{blue}{#1(}\textcolor{green}{#2(}...\textcolor{green}{)}\textcolor{blue}{)}}{
                     \IfNoValueTF {#4}  {\textcolor{blue}{#1(}\textcolor{green}{#2(}\textcolor{red}{#3(}...\textcolor{red}{)}\textcolor{green}{)}\textcolor{blue}{)}}{
                          \IfNoValueTF {#5}  {\textcolor{blue}{#1(}\textcolor{green}{#2(}\textcolor{red}{#3(}\textcolor{blue}{#4(}...\textcolor{blue}{)}\textcolor{red}{)}\textcolor{green}{)}\textcolor{blue}{)}}{
                               \IfNoValueTF {#6}  {\textcolor{blue}{#1(}\textcolor{green}{#2(}\textcolor{red}{#3(}\textcolor{blue}{#4(}\textcolor{green}{#5(}...\textcolor{green}{)}\textcolor{blue}{)}\textcolor{red}{)}\textcolor{green}{)}\textcolor{blue}{)}}{
                                    \IfNoValueTF {#7}  {\textcolor{blue}{#1(}\textcolor{green}{#2(}\textcolor{red}{#3(}\textcolor{blue}{#4(}\textcolor{green}{#5(}\textcolor{red}{#6(}...\textcolor{red}{)}\textcolor{green}{)}\textcolor{blue}{)}\textcolor{red}{)}\textcolor{green}{)}\textcolor{blue}{)}}{
                                         \IfNoValueTF {#8}  {\textcolor{blue}{#1(}\textcolor{green}{#2(}\textcolor{red}{#3(}\textcolor{blue}{#4(}\textcolor{green}{#5(}\textcolor{red}{#6(}\textcolor{blue}{#7(}...\textcolor{blue}{)}\textcolor{red}{)}\textcolor{green}{)}\textcolor{blue}{)}\textcolor{red}{)}\textcolor{green}{)}\textcolor{blue}{)}}{\textcolor{blue}{#1(}\textcolor{green}{#2(}\textcolor{red}{#3(}\textcolor{blue}{#4(}\textcolor{green}{#5(}\textcolor{red}{#6(}\textcolor{blue}{#7(}\textcolor{green}{#8(}...\textcolor{green}{)}\textcolor{blue}{)}\textcolor{red}{)}\textcolor{green}{)}\textcolor{blue}{)}\textcolor{red}{)}\textcolor{green}{)}\textcolor{blue}{)}}
                                    }
                               }
                          }
                     }
                }
            }
        }
    }
\ExplSyntaxOff
\begin{document}

Try this one instead: \HowManyArguments[Mandatory][Argument][What][Have][You][Done]

\end{document}

This is the full idea of what I'm trying to build, but without limitations.

1010011010
  • 6,357
  • 5
    You could, but you should not. LaTeX tries hard to give commands a consistent interface and the argument forms in LaTeX never depend on the values of of earlier arguments. If you want unlimited arguments use a comma separated list. That is why the syntax for color is \color[named]{red} and \color[rgb]{1,0,0} not \color[rgb]{1}{0}{0} the number of arguments doesn't depend on the colour model even though the logical number of parameters needed does depend on the model. – David Carlisle May 07 '14 at 14:26

3 Answers3

13

It would be more consistent with the design of LaTeX to use a comma separated list:

enter image description here

enter image description here

\documentclass{article}

\makeatletter
\newcommand\HowManyArguments[1]{{%
\count@\z@
\@for\tmp:=#1\do{\advance\count@\@ne}%
There are \the\count@\ arguments\par
\@for\tmp:=#1\do{(\tmp}%
\@for\tmp:=#1\do{)}}}
\makeatother


\begin{document}

\HowManyArguments{Lots,of,arguments,in,this,thread}

\end{document}

Or with colour

\documentclass{article}

\usepackage{color}
\makeatletter
\newcommand\HowManyArguments[1]{{%
\count@\z@
\@for\tmp:=#1\do{\advance\count@\@ne}%
There are \the\count@\ arguments\par
\@tempcnta\z@
\@for\tmp:=#1\do{%
\advance\@tempcnta\@ne
\textcolor[RGB]{\the\numexpr255*\@tempcnta/(\count@)\relax,
                 0,
                 \the\numexpr255-(255*\@tempcnta/(\count@))\relax}%
                {\tmp(}}%
\@tempcnta\count@
\@for\tmp:=#1\do{%
\textcolor[RGB]{\the\numexpr255*\@tempcnta/(\count@)\relax,
                 0,
                 \the\numexpr255-(255*\@tempcnta/(\count@))\relax}%
                {)}%
\advance\@tempcnta\m@ne
}}}
\makeatother


\begin{document}

\HowManyArguments{Lots,of,arguments,in,this,thread}

\end{document}
David Carlisle
  • 757,742
  • Or you could of course use a latex3 comma separated list:-) – David Carlisle May 07 '14 at 14:52
  • This looks really nice. Is it possible to use a dynamic color scheme to these? You're not using any \newcounters or anything so I don't think LaTeX keeps track of the number of arguments for reuse in other variables? Or would I have to embed this somewhere in your \@for\tmp:=#1\do{(<somewhere.here>\tmp}%? Alternatively, where can I find some good introductory reading matter to understand what's happening here? – 1010011010 May 07 '14 at 14:56
  • @1010011010 well as you see the first loop increments a counter each time, if you reset it to 0 and added the advance to each of the loops then \the\count@ will be 1,2,3 at each iteration – David Carlisle May 07 '14 at 15:10
  • @1010011010 see edit with arguments fading from blue to red – David Carlisle May 07 '14 at 15:22
  • This is 99% what I was looking for. The other 1% consists of the first parentheses (before Lots, and at the end) and the possibility to add colour to the parentheses to stress the idea of nesting. Other than that, definitely amazed. – 1010011010 May 07 '14 at 15:33
  • @1010011010 well if you change (\tmp to \tmp( the parens will come after each one and you get () at the end of you could put \ifnum@tempcnta>0(\fi to omit the first paren or... and you coudl include the paren in the \textcolor, or give it its own color as required – David Carlisle May 07 '14 at 15:36
  • I'm having trouble controlling the last parentheses. It always ends up showing only one colour, which is the one I defined last as \the\numexpr255*\@tempcnta/(\count@)\relax in that textcolor[RGB] part. – 1010011010 May 07 '14 at 15:47
  • @1010011010 see update (this is last time:-) – David Carlisle May 07 '14 at 16:03
  • Cool. It was the last line \advance\@tempcnta\m@ne that I was missing. Thanks! – 1010011010 May 07 '14 at 16:22
  • Out of interest, you said: \the\count@ will be 1,2,3 at each iteration.. how to store the total number of arguments ( \the\count@\ ) for use in the loop? – 1010011010 May 07 '14 at 23:44
  • well it's the value of \count@ after the first loop so you can save it in another register as eg @tempcntb=\count@ or save its decimal expansion in a macro \edef\foo{\the@tempcnt@} at the point the number is output before it's reset for the next loop – David Carlisle May 07 '14 at 23:49
5

An expl3 solution (just to please David). I do the computation only once, by filling two token lists and delivering them.

\documentclass{article}
\usepackage{xparse,xcolor}

\ExplSyntaxOn
\NewDocumentCommand{\HMA}{m}
 {
  \leavevmode
  \group_begin:
  \hma_process_args:n { #1 }
  \group_end:
 }

\seq_new:N \l__hma_args_seq
\tl_new:N \l__hma_opening_tl
\tl_new:N \l__hma_closing_tl
\int_new:N \l__hma_step_int
\int_new:N \l__hma_args_int

\cs_new_protected:Npn \hma_process_args:n #1
 {
  \seq_set_split:Nnn \l__hma_args_seq { , } { #1 }
  \tl_clear:N \l__hma_opening_tl
  \tl_set:Nn \l__hma_closing_tl { \dots }
  \int_zero:N \l__hma_step_int
  \int_set:Nn \l__hma_args_int { \seq_count:N \l__hma_args_seq }
  \color[RGB]{0,0,255}
  \seq_map_inline:Nn \l__hma_args_seq
   {
    \int_incr:N \l__hma_step_int
    \tl_put_right:Nx \l__hma_opening_tl
     {
      \exp_not:n { ##1 ( }
      \group_begin:
      \exp_not:N \color[RGB] { \__hma_set_color: }
     }
    \tl_put_right:Nn \l__hma_closing_tl { \group_end: ) }
   }
  \tl_use:N \l__hma_opening_tl \tl_use:N \l__hma_closing_tl
 }

\cs_new:Npn \__hma_set_color:
 {
  \int_eval:n { 255 * \l__hma_step_int / \l__hma_args_int },
  0,
  \int_eval:n { 255 - ( 255 * \l__hma_step_int / \l__hma_args_int ) }
 }

\ExplSyntaxOff

\begin{document}

\HMA{Lots,of,arguments,in,this,thread}

\end{document}

enter image description here

Just changing one line allows to avoid the dots and use the last item for the innermost parentheses.

\documentclass{article}
\usepackage{xparse,xcolor}

\ExplSyntaxOn
\NewDocumentCommand{\HMA}{m}
 {
  \leavevmode
  \group_begin:
  \hma_process_args:n { #1 }
  \group_end:
 }

\seq_new:N \l__hma_args_seq
\tl_new:N \l__hma_opening_tl
\tl_new:N \l__hma_closing_tl
\int_new:N \l__hma_step_int
\int_new:N \l__hma_args_int

\cs_new_protected:Npn \hma_process_args:n #1
 {
  \seq_set_split:Nnn \l__hma_args_seq { , } { #1 }
  \tl_clear:N \l__hma_opening_tl
  \seq_pop_right:NN \l__hma_args_seq \l__hma_closing_tl % <---- CHANGE
  \int_zero:N \l__hma_step_int
  \int_set:Nn \l__hma_args_int { \seq_count:N \l__hma_args_seq }
  \color[RGB]{0,0,255}
  \seq_map_inline:Nn \l__hma_args_seq
   {
    \int_incr:N \l__hma_step_int
    \tl_put_right:Nx \l__hma_opening_tl
     {
      \exp_not:n { ##1 ( }
      \group_begin:
      \exp_not:N \color[RGB] { \__hma_set_color: }
     }
    \tl_put_right:Nn \l__hma_closing_tl { \group_end: ) }
   }
  \tl_use:N \l__hma_opening_tl \tl_use:N \l__hma_closing_tl
 }

\cs_new:Npn \__hma_set_color:
 {
  \int_eval:n { 255 * \l__hma_step_int / \l__hma_args_int },
  0,
  \int_eval:n { 255 - ( 255 * \l__hma_step_int / \l__hma_args_int ) }
 }

\ExplSyntaxOff

\begin{document}

\HMA{Lots,of,arguments,in,this,thread}

\end{document}

enter image description here

egreg
  • 1,121,712
3

To address the OP's desire for something like Lots(of(arguments(in(this(thread))))), I created the macro \groupargs{{}{}{}{}} and give an example.

While I change colors discretely modulo the nesting level (as done in the OP's MWE), any algorithm could be inserted to calculate the color as a function of the nesting level.

\documentclass{article}
\usepackage{readarray}
\usepackage{xcolor}
\newcounter{argindex}
\newcounter{colindex}
\def\groupargs#1{\def\lparen{}\def\rparen{}\getargsC{#1}%
  \setcounter{argindex}{0}\setcounter{colindex}{0}\nextarg}
\def\nextarg{\stepcounter{argindex}\stepcounter{colindex}%
  \ifnum\theargindex>\narg\else\lparen%
  \ifnum\thecolindex=1\def\mycolor{blue}\else%
    \ifnum\thecolindex=2\def\mycolor{green}\else%
      \ifnum\thecolindex=3\def\mycolor{red}\setcounter{colindex}{0}%
  \fi\fi\fi%
  \def\lparen{(}%
  \textcolor{\mycolor}{\csname arg\romannumeral\theargindex\endcsname%
  {\def\rparen{)}\nextarg}}\rparen\fi%
}
\begin{document}
\groupargs{Mandatory Argument What Have {You Indeed} Done ...}
\end{document}

enter image description here