我有以下 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)。您的
\NewDocumentCommand
s 可能应该是内部的(即\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}