2

I've got a problem with nested macro definitions. While my use case is a bit different, what follows is a minimum (non-)working example:

What I want to do:

I want to dynamically define a group of macros \One, \Two, and \Three. They shall take the same number of arguments each, but this number of arguments should also be variable. By calling

\docsvlist{mm, One(#1), Two(#1 #2)}

I want all macros to be defined such that they take two mandatory arguments and

\One{Hi}{Hello}
\Two{Hi}{Hello}
\Three{Hi}{Hello}

to 'return'

One: One(Hi)
Two: Two(Hi Hello)
Three: One(Hi) + Two(Hi Hello)

The code:

\usepackage{xparse}
\usepackage{etextools}    

\DeclareDocumentCommand{\myDeclare}{mmm}{
    \DeclareDocumentCommand{\One}{#1}{One: #2\par}
    \DeclareDocumentCommand{\Two}{#1}{Two: #3\par}
    \DeclareDocumentCommand{\Three}{#1}{Three: #2 + #3\par}
}
\DeclareDocumentCommand{\do}{m}{
    \DeclareDocumentCommand{\do}{m}{
        %This would work for \One:
        %\DeclareDocumentCommand{\One}{#1}{One: ##1\par}
        \DeclareDocumentCommand{\do}{m}{
            %This also works for \Two:
            %\DeclareDocumentCommand{\Two}{#1}{Two: ####1\par}
            \myDeclare{#1}{##1}{####1}
            %This also does not work for \Three:
            %\DeclareDocumentCommand{\Three}{#1}{Three: ##1 + ####1\par}
        }
    }
}
\docsvlist{mm, One(#1), Two(#1 #2)}
\One{Hi}{Hello}
\Two{Hi}{Hello}
\Three{Hi}{Hello}

This produces the following output:

One: One(Two(Hi Hello))
Two: Two(Hi Hello)
Three: One(Two(Hi Hello)) + Two(Hi Hello)

What I would actually want:

One: One(Hi)
Two: Two(Hi Hello)
Three: One(Hi) + Two(Hi Hello)

My question:

What happens? I was surprised that it works at all. \Two gets defined as I want it to, but \One only gets defined correctly if I define it in the way that i have commented out. I can't find a way to define \Three correctly at all.

In the call to

        \myDeclare{#1}{##1}{####1}

the ##1 seems to get changed from One(#1) to One(####1) and then subsequently to One(Two(#1 #2)) in the definition of \One.

But why? And how could I prevent this?

Edit: The actual use case

I want to simultaneously define several mathematical functions or equalities (or something similar), as for (mock) example as follows:

\MyDefine{
    aSet, {}, 
        \Omega, \subset \Reals, 
        {a nice set},
    aFunction, O{i}, 
        f^{#1}, :\aSet \to \aSet, 
        {some $#1$-th function},
    anEquality, O{i}O{j}, 
        \aFunction[#1] \leq \aFunction[#2], \text{for $#1 \leq #2$},
        {a nice inequality}
}

This should define (among others, updated) :

\DeclareDocumentCommand{\aSet}{}{
    \Omega
}
\DeclareDocumentCommand{\aSetDefinition}{}{
    \subset \Reals
}
\DeclareDocumentCommand{\aSetDescription}{}{
    a nice set
}
\DeclareDocumentCommand{\aSetLabel}{}{def:aSet}
\DeclareDocumentCommand{\aFunction}{O{i}}{
    f^{#1}
}
\DeclareDocumentCommand{\aFunctionDefinition}{O{i}}{
    :\aSet \to \aSet
}
\DeclareDocumentCommand{\aFunctionDescription}{O{i}}{
    some $#1$-th function
}
\DeclareDocumentCommand{\aFunctionLabel}{}{def:aFunction}
\DeclareDocumentCommand{\anEquality}{O{i}O{j}}{
    \aFunction[#1] \leq \aFunction[#2]
}
...

for later use and also generate (e.g.):

\begin{align}
    \aSet& \aSetDefinition&& \text{\aSetDescription}\label{\aSetLabel}\\
    \aFunction& ...\\
    \anEquality& ...
\end{align}
  • You want \docsvlist{mm, One(##1), Two(#1 #2)} – Andrew Swann Apr 1 '17 at 18:41
  • That would work (I assume), but is not really satisfactory, right? It's a bit strange to have to include extra #s, and this should also get messy if I had more levels. – user2483681 Apr 2 '17 at 13:06
  • It's even less clear after the edit. What do you expect the definitions of \aSet, \aFunction and \anEquality be? And what's the role of “some parameters”? – egreg Apr 2 '17 at 13:09
  • @egreg Well the macros should be defined in a similar fashion as in the initial example, I thought adding the details would only be distracting. I've added the definitions now. The additional "some parameters" was really only distracting, I removed it. – user2483681 Apr 2 '17 at 13:39
1

You can keep the comma list input, if you want. Don't use etextools, if you can avoid it: expl3 has all the features you need:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\declaremacros}{>{\SplitArgument{2}{,}}+m}
 {
  \declaremacros:nnn #1
 }
\cs_new_protected:Nn \declaremacros:nnn
 {
  \NewDocumentCommand\One{#1}{#2}
  \NewDocumentCommand\Two{#1}{#3}
  \NewDocumentCommand\Three{#1}{#2 ~ + ~ #3}
 }
\ExplSyntaxOff

\declaremacros{mm, One(#1), Two(#1 #2)}

\begin{document}

\One{Hi}{Hello}

\Two{Hi}{Hello}

\Three{Hi}{Hello}

\end{document}

enter image description here

  • This does indeed look much simpler than what I came up with. I edited my question to include the actual use case, and this solution should be applicable after minor modifications. – user2483681 Apr 2 '17 at 13:07
2

I probably wouldn't use etextools and expl3 together, but here it seems that the syntax you are aiming for is making it more complicated than it could be. this produces the requested output

\documentclass{article}



\usepackage{xparse}


\DeclareDocumentCommand{\zz}{mmm}{%
    \DeclareDocumentCommand{\One}{#1}{One: #2\par}%
    \DeclareDocumentCommand{\Two}{#1}{Two: #3\par}%
    \DeclareDocumentCommand{\Three}{#1}{Three: #2 + #3\par}%
}

\zz{mm}{One(#1)}{Two(#1 #2)}

\begin{document}


\One{Hi}{Hello}
\Two{Hi}{Hello}
\Three{Hi}{Hello}

\end{document}

enter image description here

the only real differexnce in syntax is that I use {}{} rather than { , } but if the comma list is needed it would be easy to use an expl3 list processor. The brace groups look easier to read though.

  • Thanks for your help, but indeed the comma list syntax is at least wanted. I edited my question to include the actual use case, where this should be clear. – user2483681 Apr 2 '17 at 13:01

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.