\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-node}
\begin{document}
\begin{pspicture}[showgrid](-5,-5)(5,5)
\pnodes{A}(-2,3)(3,4)(2,-1)(-2,-4)(-4,0)
\def\points{(0,0)}
\foreach \x in {0,1,...,4}{%
\pscircle*[linecolor=blue](A\x){3pt}%
\xdef\points{\points+.2(A\x)}%
}
%The first line below causes errors.
%\expandafter\nodexn{\points}{B}
%\pscircle*[linecolor=red](B){3pt}
\end{pspicture}
\end{document}
我如何调用\expandafter
具有多个参数的宏?
答案1
你需要做
\expandafter\nodexn\expandafter{\points}{B}
你需要“跳过”{
否则
\expandafter\nodexn{\points}{B}
在扩展之前仅扩展{
一次(至{
) 。\nodexn
LaTeX 内核定义了一个有用的宏,\@expandtwoargs
如下所示
\def\@expandtwoargs#1#2#3{%
\edef\reserved@a{\noexpand#1{#2}{#3}}\reserved@a}
这\edef
是宏在“执行”之前的前两个参数。显然,你会想做类似的事情
\makeatletter
\let\expandtwoargs\@expandtwoargs
\makeatother
才能舒服地使用它。(当然,这对于那些不能安全完全扩展的参数不起作用。)
如果要扩展两个以上的参数,可以使用仅包含参数的临时宏:
\edef\tmp{{\argumentA}{\argumentB}{\argumentC}{\argumentD}}
然后只需要扩展一次:
\expandafter\myMacro\tmp % \tmp already contains the braces
从相同的技巧框,但完全相反的问题,即在具有许多参数的宏的末尾扩展一个参数,可以通过将所有内容塞入临时宏中的参数来解决,然后可以很容易地“跳过”:
\def\B{B}
\def\tmp{\myMacro{argument A}{argument B}}
\expandafter\tmp\expandafter{\argumentC}
否则你需要做
\expandafter\myMacro\expandafter{\expandafter a\expandafter r\expandafter g …
答案2
这是对Qrrbrbirlbel 的回答在执行宏本身之前有选择地扩展宏的一个参数。我将在这里将“扩展”理解为扩展一次,并且不假设参数只是单个标记(扩展将仅应用于参数的第一个标记;这当然可能会引起该参数的进一步扩展)。我的评论是可以扩展地做到这一点。
注意:在下面的编辑中添加了更强大的“ expandable expander
”。它也只扩展一次目标参数(第一个标记),但这可以提升为“完全扩展”。(见代码)
我们需要这些实用程序:
\def\expandArg #1#2{\expandafter\expandArgaux\expandafter{#2}{#1}}
\def\expandArgaux #1#2{#2{#1}}
\mymacro
然后想象一下,在执行之前我需要将 5 个参数中的第 3 个展开一次\mymacro
:
\expandArg {\mymacro {Not me}{Not me}}{Expand Me}{Not me}{Not me}
成功了。与Qrrbrbirlbel 的回答并且在评论中指出,这是可扩展的,因为不需要\def
。
为了显示:
\def\expandArg #1#2{\expandafter\expandArgaux\expandafter{#2}{#1}}
\def\expandArgaux #1#2{#2{#1}}
\tt
\def\mymacro #1#2#3#4#5{\meaning #3}
\def\x {\y}
\def\y {z}
\mymacro {1}{2}{\x}{4}{5}
\par
\expandArg {\mymacro {1}{2}}{\x}{4}{5}
\bye
输出:
我在评论中提到,也可以使用更加用户友好的语法:
\ExpandNth {5}\mymacro{A}{B}{C}{D}{E}{F}{G}
没有多余的括号,因此,在执行之前仅扩展第五个参数\mymacro
。
这是一种方法。如果给定N
零或更少,它会正确运行,但如果N
超过实际参数数量,则会产生错误。同样重要的是,\mymacro
应用可扩展扩展器的宏的参数之间不能留有空格。
\catcode`\_ 11
\def\ExpandNth #1%
{%
\romannumeral0\ifnum #1>0
\expandafter\ExpandNth_a
\else
\expandafter\ExpandNth_none
\fi {#1}%
}
\def\ExpandNth_none #1{ }
\def\ExpandNth_a #1#2{\ExpandNth_b {#1}{#2}}
\def\ExpandNth_b #1%
{%
\ifnum #1>1
\expandafter\ExpandNth_c
\else
\expandafter\ExpandNth_w
\fi {#1}%
}
\def\ExpandNth_c #1#2#3%
{%
\expandafter\ExpandNth_b\expandafter
{\the\numexpr #1-1}{#2{#3}}%
}%
\def\ExpandNth_w #1#2#3%
{%
\expandafter\ExpandNth_z\expandafter {#3}{#2}%
}%
% replace #3 above by \romannumeral-`0#3 for "full" expansion
\def\ExpandNth_z #1#2{ #2{#1}}%
\catcode`\_ 8
\tt
\def\mymacro #1#2#3#4#5{\meaning #1\par
\meaning #2\par
\meaning #3\par
\meaning #4\par
\meaning #5\par}
\def\a{\A} \def\A{A}
\def\b{\B} \def\B{B}
\def\c{\C} \def\C{C}
\def\d{\D} \def\D{D}
\def\e{\E} \def\E{E}
\hsize 12cm
Original \string\mymacro:\par
\mymacro \a\b\c\d\e
\medskip\hrule\medskip
With prior (once) expansion of the first argument:\par
\ExpandNth {1}\mymacro \a\b\c\d\e
\medskip\hrule\medskip
With prior (once) expansion of the second argument:\par
\ExpandNth {2}\mymacro \a\b\c\d\e
\medskip\hrule\medskip
With prior (once) expansion of the third argument:\par
\ExpandNth {3}\mymacro \a\b\c\d\e
\medskip\hrule\medskip
With prior (once) expansion of the fourth argument:\par
\ExpandNth {4}\mymacro \a\b\c\d\e
\medskip\hrule\medskip
With prior (once) expansion of the fifth argument:\par
\ExpandNth {5}\mymacro \a\b\c\d\e
\bye
输出:
答案3
对于这个特定的应用程序你可以简单地
\newcommand{\nodexnX}[1]{\expandafter\nodexn\expandafter{#1}}
并调用\nodexnX{\points}{B}
或者你可以进一步重新定义,\nodexn
以便它完全扩展其第一个参数
\let\PSTRICKSnodexn\nodexn
\renewcommand{\nodexn}[1]{%
\begingroup\edef\x{\endgroup
\noexpand\PSTRICKSnodexn{#1}}\x
}
LaTeX3 内核已\exp_args:Nx
隐式添加了\cs_generate_variant:Nn
:
\usepackage{expl3}
\ExplSyntaxOn
\cs_set_eq:NN \pstricks_nodexn:nn \nodexn
\cs_generate_variant:Nn \pstricks_nodexn:nn { x }
\cs_set_eq:NN \nodexn \pstricks_nodexn:xn
\ExplSyntaxOff
如果你需要完全扩展第二个参数,你可以这样做
\cs_set_eq:NN \pstricks_nodexn:nn \nodexn
\cs_generate_variant:Nn \pstricks_nodexn:nn { xx }
\cs_set_eq:NN \nodexn \pstricks_nodexn:xx
在这两种情况下,您都\nodexn
在调用原始宏之前有效地重新定义以扩展其参数。
2022 年新增
在下一个 LaTeX 内核中,它将可用\ExpandArgs
,并且
\ExpandArgs{x}\nodexn{\points}{B}
就可以了。这是 的一个接口\exp_args:Nx
,这意味着下一个标记将被跳过,并且后面括号组的内容将完全展开。
您还想充分扩展第二个论点吗?
\ExpandArgs{xx}\nodexn{\points}{\foo}
会做。
只要\exp_args:N<characters>
存在,就可以使用\ExpandArgs{<characters>}
。字符包括
N
表示“跳过一个标记”n
表示“跳过支撑组”x
使用以下方法完全展开支撑组的内容\edef
e
使用以下方法完全展开支撑组的内容\expanded
f
递归地遍历支撑组的内容,直到找到不可展开的标记o
展开支撑组中的第一个标记
如果不存在所需的特定组合,则没有“官方”用户界面来创建它,但可以这样做
\ExplSyntaxOn
\exp_args_generate:n { <characters>, ... }
\ExplSyntaxOff
可以一次生成多个组合,字符串之间用逗号分隔。
答案4
和functional
包中,棘手的参数扩展可以用直观的函数组合来代替,这与其他编程语言类似,例如Lua
:
\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-node}
\usepackage{functional}
\Functional{scoping=true} % make every function become a group
\begin{document}
\IgnoreSpacesOn
\PrgNewFunction \NodeXn { m m } {
\nodexn {#1} {#2}
}
\IgnoreSpacesOff
\begin{pspicture}[showgrid](-5,-5)(5,5)
\pnodes{A}(-2,3)(3,4)(2,-1)(-2,-4)(-4,0)
\def\points{(0,0)}
\foreach \x in {0,1,...,4}{%
\pscircle*[linecolor=blue](A\x){3pt}%
\xdef\points{\points+.2(A\x)}%
}
\NodeXn{\Value\points}{B}
\pscircle*[linecolor=red](B){3pt}
\end{pspicture}
\end{document}