怎么了

怎么了

我有以下 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}

然而此时它出错了:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! 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

我不确定哪里出了问题,因为定义仅在调用之前创建一次\prop_map_function。想知道如何修复此问题,以便我可以进行嵌套函数调用,嵌套函数调用可能使用#1父作用域中的此类函数。

笔记,如果将命令移到嵌套之外,它就会起作用:

\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}

但如果可能的话,我想按照原来的方式去做。

答案1

怎么了

  • 您定义一个已经定义的命令。\NewDocumentCommand如果命令已经定义,则应该抛出错误。此时您可以使用\DeclareDocumentCommand 并且不会遇到该问题。
  • #1在内部函数中使用(这样您就永远不会使用属性列表中的内容b)。要调用在函数内定义的函数的参数,请#在嵌套级别前加上一个(##1在本例中如此)。
  • 你滥用了函数签名之类的 expl3 概念。A:N意味着一个代币是预期的(控制字),所以你不应该将其分组。实际上,这意味着你应该用\prop_new:N {\my:pl:a}替换\prop_new:N \my:pl:a
  • 您引入了自己的命名约定,这会使代码变得难以阅读且风格糟糕。变量的 expl3 命名方案将是\<local or global>_[_]<module>_<variable>_<type>,例如\l_pollard_a_prop。对于控制序列,您可以使用\[__]<module>_<name>:<signature>,例如,\pollard_mapper_fna:nn它具有采用两组的有效签名。
  • 您正在混合不同级别的接口。代码级别 (expl3) 语法(与预期完全不同)和文档级别语法 (xparse)。您的\NewDocumentCommands 可能应该是内部的(即\cs_new:Npn)。

为何发生

每个项目都会调用包装函数,但即使在第一个之后,该函数也已经定义。这意味着您\my:wrapper:fna在每个项目上使用的包装函数在每次调用时都会尝试定义\my:wrapper:fnb为新命令。这会引发记录的错误。

错误的输出是由于您使用了#1而不是造成的##1。因此您应该替换它。

我会推荐使用吗\DeclareDocumentCommand

不是,因为每次调用 a 的包装器时,都会对整个属性列表 b 使用包装函数。

更好的代码

\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}

您的代码(可编译)

\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}

相关内容