如何在宏定义中 \expandafter a \let#1

如何在宏定义中 \expandafter a \let#1

有时我想重新定义一些CS在一个范围内,通常是宏定义。例如:

\def[[cs名称>]]{

    [[重新定义一些 cs]]

    [[该宏的实际功能]]

    [[恢复重新定义的 cs]]

}

主要需要做的是定义Redefine和的宏Recover,我们将它们称为\redefine\recover

对于恢复来说,几乎不存在冲突CS应该用来存储CS要重新定义,并且它们的名称应该是相对的。这里我使用“其 csname 的 csname”:

\def\redefine#1#2{
    \expandafter \let \csname\string#1\endcsname #1 \relax
    \def#1{#2}
}

哪儿#1CS被重新定义。

现在发现,原来的意思已经无法挽回了。

\def\recover#1{
    \let #1 \csname\string#1\endcsname
}

在 之前似乎\csname\string#1\endcsname无法展开\let,因为# 1是两个不同的标记,但当且仅当它们连续出现时,在宏定义中将其视为参数替换。同时\expandafter只跳过 1 个标记。

也许,\def\let在大多数情况下不能使用,我仍然想知道当第一个标记是参数时,有什么方法可以使第二个标记在第一个标记之前扩展?


IE

定义了一些较短的原始 cs:

\let\epaf\expandafter
\let\str\string
\let\nep\noexpand
\let\cs\csname
\let\sc\endcsname
...

一个宏\mfont,解析一个句子直到\relax,并设置大量的字体属性,并且使单个cs同时设置拉丁字体和unicode字体。它使用大量的原始cs来解析句子,如果保留长名称,定义很难阅读。

\mfont在从到的块之后\relax,应该恢复 shoter 名称。\mfont应该为全局定义字体,但较短的名称应该仅在范围内有效\mfont

答案1

在此处输入图片描述

你有虚假的空间,并且缺失\expandafter

% no space!!!!
\def\redefine#1#2{%
    \expandafter \let \csname\string#1\endcsname #1%
    \def#1{#2}%
}




% no space!!!!
\def\recover#1{%
% missing \expandafter 
    \expandafter \let \expandafter #1\csname\string#1\endcsname
}


{\tt \string\sin=\meaning\sin}

\redefine\sin{hello}

{\tt \string\sin=\meaning\sin}

\recover\sin

{\tt \string\sin=\meaning\sin}

\bye

答案2

除了虚假的空间,你的\recover代码

\let #1 \csname\string#1\endcsname

如果你打电话,\recover\foo你会得到

\let\foo\csname\string\foo\endcsname

因此,您要将其重新定义\foo\csname,打印\foo(作为字符串)并收到有关位置错误的错误消息\endcsname

你需要

\expandafter\let\expandafter#1\csname\string#1\endcsname

所以形成了 token \let开始行动。

替代方法,您无需担心虚假空格和\expandafter

参数类型c表示“形成一个控制序列标记”(它\csname...\endcsname在内部使用并应用正确的\expandafter序列。也\cs_set:Npn相当于\def(实际上\long\def,但在这种情况下并不重要)。

\input expl3-generic

\ExplSyntaxOn
\cs_new_protected:Npn \redefine #1 #2
 {
  % save the current meaning of #1
  \cs_set_eq:cN { \token_to_str:N #1 } #1
  \cs_set:Npn #1 { #2 }
 }
\cs_new_protected:Npn \recover #1
 {
  \cs_set_eq:Nc #1 { \token_to_str:N #1 }
 }

\ExplSyntaxOff

{\tt \string\sin=\meaning\sin}

\redefine\sin{hello}

{\tt \string\sin=\meaning\sin}

\recover\sin

{\tt \string\sin=\meaning\sin}

\bye

在此处输入图片描述

如果你不想走这条路,你可以也应该定义自己的语法糖。expl3很多及其\cs_set_eq:NN变体。

\def\cslet#1{\expandafter\let\csname#1\endcsname}
\def\letcs#1#2{\expandafter\let\expandafter#1\csname#2\endcsname}

\def\redefine#1#2{%
  % save the current meaning of #1
  \cslet{\string#1}#1%
  % redefine #1
  \def#1{#2}%
}
\def\recover#1{\letcs#1{\string#1}}

{\tt \string\sin=\meaning\sin}

\redefine\sin{hello}

{\tt \string\sin=\meaning\sin}

\recover\sin

{\tt \string\sin=\meaning\sin}

\bye

答案3

为了应对隐式空间,\let我建议这样做:

\def\redefine#1{%
  \expandafter\futurelet\csname\string#1\endcsname\def#1%
}%
\def\exchange#1#2{#2#1}%
\def\recover#1{%
  \expandafter\exchange\expandafter{\csname\string#1\endcsname}{\let#1= }%
}%

\def\foobar{foo}
\foobar

\redefine\foobar{bar}
\foobar

\recover\foobar
\foobar

\bigskip
Doing the implicit space game:
\bigskip

\exchange{ }{\let\foobar= }%
A\foobar A

\redefine\foobar{bar}
B\foobar B

\recover\foobar
C\foobar C

\bye

在此处输入图片描述

或者只是通过\begingroup..\endgroup或进行一些范围界定{..}

\def\foobar{foo}%
\foobar

\begingroup
\def\foobar{bar}%
\foobar
\endgroup

\foobar

{%
\def\foobar{bar}%
\foobar
}%

\foobar

\bye

相关内容