# How to define a macro that takes the definition of a macro as an argument

We would like to define a macro \ellipsis that takes four argument and has the following behaviour:

\ellipsis{x^{#DUMMY#}}{0}{5}{+}


and outputs:

the pattern string #DUMMY# (which doesn't have to be this exact string) has to be replaced by the second and third argument. So the first argument is the definition of a macro all by itself.

We have tried a couple of things but always end up using two different macros to obtain the desired behaviour. For example doing

\newcommand{\ellipMacro}[1]{x^{#1}}
\newcommand{\ellip}[4]{\csuse{#1}{#2}#4\ldots #4 \csuse{#1}{#3}}


This uses the control sequence \csuse from the package etoolbox (we are fine with using any packages).

We would like to do this in just one command, thus, the definition of the inner macro (x^{#DUMMY}) needs to be placed within the definition of the larger macro.

Please include any ideas on how to do this you might have.

• I do not understand what dummy is supposed to do in this macro. From your definition \ellipsis{x^{#DUMMY#}}{0}{5}{+} there is nothing left to question inside of dummy as to what it does. – Bob Aug 11 '19 at 1:58
• #DUMMY# is a placeholder, it should be substituted with the second and third arguments – Lucas Vaca Aug 11 '19 at 2:00

## 4 Answers

This is an adaptation of my answer at How to make a command to automate creation of prime factorization-like products?

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

\ExplSyntaxOn
\NewDocumentCommand{\elliptic}{O{i}mmmm}
{% #1 = item to substitute
% #2 = main term
% #3 = first index
% #4 = last index
% #5 = operation
\group_begin:
\lucas_elliptic:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 }
\group_end:
}
\tl_new:N \l__lucas_elliptic_term_tl
\cs_generate_variant:Nn \cs_set:Nn { NV }
\cs_new:Nn \lucas_elliptic:nnnnn
{
\tl_set:Nn \l__lucas_elliptic_term_tl { #2 }
\regex_replace_all:nnN
{ #1 } % search
{ \cB\{\cP\#1\cE\} } % replace
\l__lucas_elliptic_term_tl % what to act on
\cs_set:NV \__lucas_elliptic_term:n \l__lucas_elliptic_term_tl
\__lucas_elliptic_term:n { #3 }
#5 \dots #5
\__lucas_elliptic_term:n { #4 }
}
\ExplSyntaxOff

\begin{document}

$\elliptic{x^{i}}{0}{5}{+}$

$\elliptic{x_{i}}{0}{5}{+}$

$\elliptic[k]{(x_{k}+y_{k}i)}{1}{n}{}$

\end{document}


If you're happy to use #1 for the placeholder, this can be simplified:

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

\ExplSyntaxOn
\NewDocumentCommand{\elliptic}{mmmm}
{% #1 = main term
% #2 = first index
% #3 = last index
% #4 = operation
\group_begin:
\lucas_elliptic:nnnn { #1 } { #2 } { #3 } { #4 }
\group_end:
}
\cs_new:Nn \lucas_elliptic:nnnn
{
\cs_set:Nn \__lucas_elliptic_term:n { #1 }
\__lucas_elliptic_term:n { #2 }
#4 \dots #4
\__lucas_elliptic_term:n { #3 }
}
\ExplSyntaxOff

\begin{document}

$\elliptic{x^{#1}}{0}{5}{+}$

$\elliptic{x_{#1}}{0}{5}{+}$

$\elliptic{(x_{#1}+y_{#1}i)}{1}{n}{}$

\end{document}

• Thanks. Shouldn't the two \cs_new:Nn be changed to \cs_new_protected:Nn, in an ideal world? – frougon Aug 11 '19 at 15:29
• @frougon Not necessarily. – egreg Aug 11 '19 at 16:01
• Neither \lucas_elliptic:nnnnn (1st example) nor \lucas_elliptic:nnnn (2nd example) can produce a meaningful result when used in an expansion-only context, right? Defining them with \cs_new_protected:Nn would be a clear indication of this fact to anyone reading their definition. No need to delve into their implementation to discover it. What do you gain here by not using \cs_new_protected:Nn? Do you fear that with \cs_new_protected:Nn, people would be encouraged to write calls inside \edef or so where the arguments are not adequately protected against expansion? – frougon Aug 11 '19 at 20:10

For the example given where the argument comes at the end of the placeholder, you do not need to define any internal command, but for the general case the form \ellipsisb takes as the first argument the body of any one-argument command definition. This allows the 0^2...5^2 form shown at the end.

\documentclass{article}

\begin{document}

\newcommand\ellipsis[4]{#1{#2}#4\cdots#4#1{#3}}

$\ellipsis{x^}{0}{5}{+}$

\newcommand\ellipsisb[4]{%
\def\tmp##1{#1}\tmp{#2}#4\cdots#4\tmp{#3}}

$\ellipsisb{x^{#1}}{0}{5}{+}$

$\ellipsisb{{#1}^2}{0}{5}{+}$

\end{document}


Perhaps I don't understand what you want but as far as I can see you don't need \csuse here and can define:

\newcommand\ellip[4]{{#1}^{#3}#2\dots#2{#1}^{#4}}


This way $\ellip x+04$ and $\ellip y-{-1}2$, respectively, produce

If you really do need a fancier version that supports a macro then I suggest not putting the macro in the exponent and, instead, just replace x^ with \csuse{#1}:

\newcommand\fancyellip[4]{\csuse{#1}{#3}#2\dots#2\csuse{#1}{#4}}


so that now $\fancyellip{xint}-{1}2$ produces

for an appropriate definition of \xint.

Here is the full code:

\documentclass{article}

\newcommand\ellip[4]{{#1}^{#3}#2\dots#2{#1}^{#4}}

\usepackage{etoolbox}
\newcommand\fancyellip[4]{\csuse{#1}{#3}#2\dots#2\csuse{#1}{#4}}
\newcommand\xint[1]{\int_{0}^{#1}x\,dx}

\begin{document}

$\ellip x+04$

$\ellip y-{-1}2$

\bigskip

$\fancyellip{xint}-{1}2$
\end{document}

• you are using two \newcommands to get the ellipsis, I clearly stated that I want it to be all within just one definition. – Lucas Vaca Aug 11 '19 at 2:04
• @LucasVaca Sorry, but from your question it is not clear to me what you want. Can you add more detail? The definition \ellip in my code is also one command, and seems to produce your desired output, so I don't even understand your comment. – user30471 Aug 11 '19 at 2:06
• I would like to not have to use another \newcommand in order to produce another ellipsis. In my question, \ellipsis is only defined once and can be used to define more than one macro. In your example you would have to define a new different macro for each different ellipsis. – Lucas Vaca Aug 11 '19 at 2:15

My macro

\replaceiandreplicate{<term with i>}%
{<loop-start-index>}%
{<loop-end-index>}%
{<separator>}%
{<end index>}


presented in the discussion Loop code for repeated sums and in the discussion How to make a command to automate creation of prime factorization-like products? might be of interest to you:

\documentclass{article}

\makeatletter
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo,
%%    \UD@PassFirstToSecond, \UD@Exchange, \UD@removespace
%%    \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%%    \UD@CheckWhetherLeadingSpace, \UD@ExtractFirstArg
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has leading
%%                        catcode-1-token>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has no leading
%%                        catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
\romannumeral0\expandafter\UD@secondoftwo\expandafter{\expandafter{%
\string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@firstoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% \UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is a
%%                               space-token>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is not
%%                               a space-token>}%
\newcommand\UD@CheckWhetherLeadingSpace[1]{%
\romannumeral0\UD@CheckWhetherNull{#1}%
{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
{\expandafter\UD@secondoftwo\string{\UD@CheckWhetherLeadingSpaceB.#1 }{}}%
}%
\newcommand\UD@CheckWhetherLeadingSpaceB{}%
\long\def\UD@CheckWhetherLeadingSpaceB#1 {%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
{\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
{\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter}\expandafter\expandafter
\expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%%   \UD@ExtractFirstArg{ABCDE} yields  {A}
%%
%%   \UD@ExtractFirstArg{{AB}CDE} yields  {AB}
%%.............................................................................
\newcommand\UD@RemoveTillUD@SelDOm{}%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
\newcommand\UD@ExtractFirstArg[1]{%
\romannumeral0%
\UD@ExtractFirstArgLoop{#1\UD@SelDOm}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{ #1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%=============================================================================
%% \DefineReplacementMacro{<replacement-macro>}%
%%                        {<internal helper-macro>}%
%%                        {<single non-explicit-space/non-explicit-brace-token to replace>}%
%%
%%  defines <replacement-macro> to fetch two arguments,
%%  #1 = <replacement for item to replace>
%%  #2 = <token sequence with item to replace>
%%  , and to deliver after two expansion-steps:
%%  <token sequence with all instances of
%%  <single non-explicit-space/non-explicit-brace-token to replace> replaced
%%  by <replacement for item to replace>. >
%%
%% Internally an <internal helper-macro> is needed.
%%
%%  (!!! <replacement-macro> does also replace all pairs of matching
%%       explicit character tokens of catcode 1/2 by matching brace-tokens!!!
%%       Under normal circumstances this is not a problem as under normal
%%       circumstances { and } are the only characters of catcode 1 respective 2.)
%%-----------------------------------------------------------------------------
\newcommand\DefineReplacementMacro[3]{%
\newcommand#2{}\long\def#2##1#3{}%
\newcommand#1[2]{%
\romannumeral0\UD@ReplaceAllLoop{##2}{##1}{}{#2}{#3}%
}%
}%
\newcommand\UD@ReplaceAllLoop[5]{%
\UD@CheckWhetherNull{#1}{ #3}{%
\UD@CheckWhetherLeadingSpace{#1}{%
\expandafter\UD@ReplaceAllLoop
\expandafter{\UD@removespace#1}{#2}{#3 }{#4}{#5}%
}{%
\UD@CheckWhetherBrace{#1}{%
\expandafter\expandafter\expandafter\UD@PassFirstToSecond
\expandafter\expandafter\expandafter{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral0\expandafter\UD@ReplaceAllLoop
\romannumeral0\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{#2}{}{#4}{#5}%
}{#3}}%
{\expandafter\UD@ReplaceAllLoop\expandafter{\UD@firstoftwo{}#1}{#2}}%
{#4}{#5}%
}{%
\expandafter\UD@CheckWhetherNoReplacement
\romannumeral0\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{#1}{#2}{#3}{#4}{#5}%
}%
}%
}%
}%
\newcommand\UD@CheckWhetherNoReplacement[6]{%
\expandafter\UD@CheckWhetherNull\expandafter{#5#1#6}%
{%
\expandafter\UD@ReplaceAllLoop
\expandafter{\UD@firstoftwo{}#2}{#3}{#4#1}{#5}{#6}%
}{%
\expandafter\UD@ReplaceAllLoop
\expandafter{\UD@firstoftwo{}#2}{#3}{#4#3}{#5}{#6}%
}%
}%
%%=============================================================================
%% \UD@ReplaceAlli -- Replace all "i" in undelimited Argument:
%%
%%   \UD@ReplaceAlli{<replacement for i>}{<token sequence with i>}
%%   yields  <token sequence with all i replaced by replacement for i>
%%
%%  <replacement for i> may contain i.
%%
%%  (This routine does also replace all pairs of matching explicit
%%   character tokens of catcode 1/2 by matching braces!!!)
%%
%%  The letter "i" as item to replace is hard-coded.
%%  You cannot replace öetters other than I with this macro.
%%.............................................................................
\DefineReplacementMacro{\UD@ReplaceAlli}{\UD@gobbletoi}{i}%
%%
%%=============================================================================
%% \replaceiandreplicate{<term with i>}%
%%                      {<loop-start-index>}%
%%                      {<loop-end-index>}%
%%                      {<separator>}%
%%                      {<end index>}
%%
%% e.g.,
%%
%%  \replaceiandreplicate{p_i^{\epsilon_i}}{1}{3}{\cdots}{n}
%%.............................................................................
\newcommand\replaceiandreplicate[5]{%
\romannumeral0\expandafter\expandafter
\expandafter            \UD@Exchange
\expandafter\expandafter
\expandafter{%
\UD@ReplaceAlli{#5}{#1}%
}{%
\replaceiandreplicateloop{#3}{#2}{#1}#4%
}%
}%
\newcommand\replaceiandreplicateloop[3]{%
\ifnum#1<#2 %
\expandafter\UD@firstoftwo
\else
\expandafter\UD@secondoftwo
\fi
{ }{%
\expandafter\expandafter
\expandafter            \UD@Exchange
\expandafter\expandafter
\expandafter{%
\UD@ReplaceAlli{#1}{#3}%
}{%
\expandafter\replaceiandreplicateloop
\expandafter{\number\numexpr\number#1-1\relax}{#2}{#3}%
}%
}%
}%
\makeatother

\parindent=0ex

\begin{document}

\begin{verbatim}
$\replaceiandreplicate{x^{i}}{0}{0}{+\ldots+}{5}$
\end{verbatim}

yields:\bigskip

$\replaceiandreplicate{x^{i}}{0}{0}{+\ldots+}{5}$

\bigskip\hrule

\begin{verbatim}
$\replaceiandreplicate{\if i0\else+\fi x^{i}}{0}{4}{}{5}$
\end{verbatim}

yields:\bigskip

$\replaceiandreplicate{\if i0\else+\fi x^{i}}{0}{4}{}{5}$

\bigskip\hrule

\begin{verbatim}
$\replaceiandreplicate{\ifnum i=-2 \else+\fi x^{\ifnum i<0(i)\else i\fi}}{-2}{4}{}{5}$
\end{verbatim}

yields:\bigskip

$\replaceiandreplicate{\ifnum i=-2 \else+\fi x^{\ifnum i<0(i)\else i\fi}}{-2}{4}{}{5}$

\bigskip\hrule

\begin{verbatim}
$\replaceiandreplicate{p_{i}^{\epsilon_{i}}}{1}{3}{\cdots}{n}$
\end{verbatim}

yields:\bigskip

$\replaceiandreplicate{p_{i}^{\epsilon_{i}}}{1}{3}{\cdots}{n}$

\bigskip\hrule

\begin{verbatim}
$\replaceiandreplicate{\if in+\fi p_{i}^{\epsilon_{i}}\if in\else+\fi}% {1}% {3}% {\cdots}% {n}$
\end{verbatim}

yields:\bigskip

$\replaceiandreplicate{\if in+\fi p_{i}^{\epsilon_{i}}\if in\else+\fi}{1}{3}{\cdots}{n}$

\end{document}


Please don't nest calls to \replaceiandreplicate within the first argument of \replaceiandreplicate. ;-)