1

I have the following MWE:

\documentclass[a4paper]{article}

\usepackage[english]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn

\begin{document}

\NewDocumentCommand\my:mapper:fna{mm}{
  \typeout{#1}
  \typeout{#2}

  \NewDocumentCommand\my:mapper:fnb{mm}{
    \typeout{#1}
    \typeout{#2}
  }

  \prop_map_function:NN \my:pl:b \my:mapper:fnb
}

\prop_new:N {\my:pl:a}
\prop_put:Nnn \my:pl:a {fooa} {baza}
\prop_put:Nnn \my:pl:a {foob} {bazb}
\prop_put:Nnn \my:pl:a {fooc} {bazc}

\prop_new:N {\my:pl:b}
\prop_put:Nnn \my:pl:b {xooa} {yaza}
\prop_put:Nnn \my:pl:b {xoob} {yazb}
\prop_put:Nnn \my:pl:b {xooc} {yazc}

\prop_map_function:NN \my:pl:a \my:mapper:fna

\end{document}

It errors at this point however:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "xparse/command-already-defined"
!
! Command '\my:mapper:fnb' already defined!
!
! See the LaTeX3 documentation for further information.
!
! For immediate help type H <return>.
!...............................................

l.35 \prop_map_function:NN \my:pl:a \my:mapper:fna

I am not sure what is wrong because the definition is created only one time just before the \prop_map_function call. Wondering how to fix this so I can do nested function calls where the nested function call can potentially use #1 and such from parent scopes.

Note, it does work if the command is moved outside of the nesting:

\documentclass[a4paper]{article}

\usepackage[english]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn

\begin{document}

\NewDocumentCommand\my:mapper:fnb{mm}{
  \typeout{#1}
  \typeout{#2}
}

\NewDocumentCommand\my:mapper:fna{mm}{
  \typeout{#1}
  \typeout{#2}

  \prop_map_function:NN \my:pl:b \my:mapper:fnb
}

\prop_new:N {\my:pl:a}
\prop_put:Nnn \my:pl:a {fooa} {baza}
\prop_put:Nnn \my:pl:a {foob} {bazb}
\prop_put:Nnn \my:pl:a {fooc} {bazc}

\prop_new:N {\my:pl:b}
\prop_put:Nnn \my:pl:b {xooa} {yaza}
\prop_put:Nnn \my:pl:b {xoob} {yazb}
\prop_put:Nnn \my:pl:b {xooc} {yazc}

\prop_map_function:NN \my:pl:a \my:mapper:fna

\end{document}

But I would like to do it the original way if possible.

1
  • 2
    In case you are not aware, you are not using the naming conventions of expl3.
    – Manuel
    Mar 24, 2018 at 18:02

1 Answer 1

3

What is wrong

  • You define a command you already defined. And \NewDocumentCommand is supposed to throw an error if a command is already defined. At this point you could use \DeclareDocumentCommand and would not encounter that problem.
  • You use #1 in the inner function (so that you will never use the content from property list b). To call arguments of a function that is defined within a function prepend a # for the level of nesting (so ##1 in this case).
  • You are abusing expl3 concepts like function signatures. A :N means that one token is expected (a control word), so you should not group it. In practice that means you should replace \prop_new:N {\my:pl:a} by \prop_new:N \my:pl:a.
  • You are introducing own naming conventions which make code kind of unreadable and bad style. The expl3 naming scheme for variables would be \<local or global>_[_]<module>_<variable>_<type>, e.g. \l_pollard_a_prop. For control sequences you would use \[__]<module>_<name>:<signature>, e.g. \pollard_mapper_fna:nn which has a valid signatures taking two groups.
  • You are mixing different levels of interface. The code level (expl3) syntax (completely different than intended) and the document level syntax (xparse). Your \NewDocumentCommands should probably be internal (i.e. \cs_new:Npn).

Why it is happening

A wrapper function is called on each item, but even after the first one the function is already defined. That means you are using \my:wrapper:fna on each item which tries to define \my:wrapper:fnb as a new command at each invocation. This throws the documented error.

The wrong output is caused by your usage of #1 instead of ##1. So you should replace this.

Would I recommend using \DeclareDocumentCommand?

No, because you are using a wrapper function on the entire property list b each time you call the wrapper for a.

Better code

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{xparse} % loads expl3

\ExplSyntaxOn
\prop_new:N \l_pollard_a_prop
\prop_new:N \l_pollard_b_prop
\cs_new:Npn \pollard_wrappera:nn #1#2
    {
      \noindent #1\\
      #2\\
      \cs_set:Npn \pollard_wrapperb:nn ##1##2
            {
                \noindent
                - ##1\\
            - ##2\par
            }
      \prop_map_function:NN \l_pollard_b_prop \pollard_wrapperb:nn
    }

\NewDocumentCommand { \puttopropa } { m m }
    {
        \prop_put:Nnn \l_pollard_a_prop { #1 } { #2 }
    }
\NewDocumentCommand { \puttopropb } { m m }
    {
        \prop_put:Nnn \l_pollard_b_prop { #1 } { #2 }
    }
\NewDocumentCommand { \processlista } { }
    {
        \prop_map_function:NN \l_pollard_a_prop \pollard_wrappera:nn
    }
\ExplSyntaxOff

\begin{document}
\puttopropa{fooa}{baza}
\puttopropa{foob}{bazb}
\puttopropa{fooc}{bazc}
\puttopropb{xooa}{yaza}
\puttopropb{xoob}{yazb}
\puttopropb{xooc}{yazc}
\processlista
\end{document}

Your code (compilable)

\documentclass[a4paper]{article}

\usepackage[english]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn

\begin{document}

\NewDocumentCommand\my:mapper:fna{mm}{
  \typeout{#1}
  \typeout{#2}

  \DeclareDocumentCommand\my:mapper:fnb{mm}{
    \typeout{##1}
    \typeout{##2}
  }

  \prop_map_function:NN \my:pl:b \my:mapper:fnb

}

\prop_new:N {\my:pl:a}
\prop_put:Nnn \my:pl:a {fooa} {baza}
\prop_put:Nnn \my:pl:a {foob} {bazb}
\prop_put:Nnn \my:pl:a {fooc} {bazc}

\prop_new:N {\my:pl:b}
\prop_put:Nnn \my:pl:b {xooa} {yaza}
\prop_put:Nnn \my:pl:b {xoob} {yazb}
\prop_put:Nnn \my:pl:b {xooc} {yazc}

\prop_map_function:NN \my:pl:a \my:mapper:fna

\end{document}
6
  • Plus \prop_new:N {\my:pl:a}, plus \my:mapper:fnb using #1 #2 instead ##1 ##2, plus the naming conventions.
    – Manuel
    Mar 24, 2018 at 18:05
  • In relation to your last point in the first section, I am confused as to why: tex.stackexchange.com/questions/422985/…
    – Lance
    Mar 24, 2018 at 18:16
  • Thank you for pointing out the little details, it helps in learning how to do this. I am seeing just how fine-grained all the syntax is which I overlooked initially.
    – Lance
    Mar 24, 2018 at 18:17
  • @LancePollard See my update.
    – TeXnician
    Mar 24, 2018 at 18:22
  • @Manuel Did I miss anything?
    – TeXnician
    Mar 24, 2018 at 18:22

You must log in to answer this question.

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