好吧,这个想法在我脑子里已经酝酿了一段时间,但还没有结果,所以我在这里问一下。在什么地方有用\edef\foo#1{..}
?它可以有什么应用?它到底有用吗?
这是一个例子。\foo
经过一次扩展后,参数将增加一万倍。当然,这可能可以用另一种方式来实现,但这似乎是一个很好的例子。
\def\byten#1{#1#1#1#1#1#1#1#1#1#1}
\edef\foo#1{\byten{\byten{\byten{\byten{#1}}}}}
Ten thousand letters: \foo{a\hskip0ptplus1pt}
\bye
但除此之外,我一直在寻找使用的机会\edef\foo#1
,但还没有出现。
为了使这个问题更容易回答,以防有些申请没有出现,或者对这个问题不感兴趣,也可以这样回答您曾见过\edef
这样使用吗?或者例如在完整的 TeX Live 安装中这有什么用吗?
笔记
问题不够清楚,egreg 和 Heiko 的建议都是可以接受的答案,因为它们是\edef
带参数的用法。但是,我正在寻找的是参数位于宏的参数内的情况,该宏在\edef
ed 时会展开(就像我的例子一样)。我不知道如何写清楚,请随意编辑问题。
答案1
在 TeX Live 2015 中搜索要定义的命令和参数的\edef
或\xdef
(全局变体)并过滤掉可能的误报(当命令由 构造时\csname
):
egrep -r '\\[ex]def\\[a-zA-Z@]+#1' texmf-dist/tex/ | grep -v '\\[ex]def\\csname'
结果是 219 行。
我不想讨论所有的发现,因此我仅限于举几个例子。
\TextOrMath
LaTeX 内核的示例( latex.ltx
)
最近,\TextOrMath
LaTeX 内核添加了宏:
\edef\TextOrMath#1#2{%
\expandafter\noexpand\csname TextOrMath\space\endcsname
{#1}{#2}}
这里, 的\edef
目的是构造一个带有空格的宏名:\TextOrMath␣
。如果空格是一个字母,定义会更简单:
\def\TextOrMath#1#2{\TextOrMath␣{#1}{#2}}
但是,这在空间的通常类别代码中是不可能的。使用\def
和很多的替代方案\expandafter
更麻烦:
\expandafter\def\expandafter\TextOrMath
\expandafter#\expandafter1\expandafter#\expandafter2\expandafter{%
\csname TextOrMath\space\endcsname{#1}{#2}%
}
因此,\edef
对定义文本的非论证部分进行处理。为了清楚起见,论证是不是在定义过程中用\edef
、进行扩展#1
的都是#9
不可扩展的标记。
\split@err
包装示例amsmath
在包中可以找到另一个示例amsmath
:
\edef\split@err#1{%
\@nx\@amsmath@err{%
\string\begin{split} won't work here%
}{%
\@xp\@nx\csname
Did you forget a preceding \string\begin{equation}?^^J%
If not, perhaps the `aligned' environment is what
you want.\endcsname}%
}
这里,该参数根本没有被使用,它被忽略作为错误恢复的一部分。
\mleftright@Def
包装示例mleftright
包中mleftright
有一个例子,其中参数使用了三次:
\edef\mleftright@Def#1{%
\noexpand\ltx@IfUndefined{%
\noexpand\expandafter\noexpand\ltx@gobble\noexpand\string#1%
}{%
\expandafter\noexpand\mleftright@Def#1%
}{%
\noexpand\@PackageError{mleftright}{%
Command \noexpand\string#1 already defined%
}\noexpand\@ehd
\noexpand\ltx@gobble
}%
}
扩展的目的在于\mleftright@Def
定义内部。以前,它被定义为\protected\def
或\DeclareRobustCommand*
,\def
具体取决于可用的方法(e-TeX、LaTeX 或两者都不是)。
參數#1
,...
在定义时,参数占位符(#1
,#2
, ... ,#9
)只是两个不可扩展的标记,即井号#
和数字。因此,或1
之间9
没有区别,因为无法扩展不可扩展的标记。\edef
\def
\edef
当宏为用过的, 那是后宏的定义。
答案2
在完全错误地理解了这个问题之后,我重写了我的答案,以展示如何\edef
使用参数来“修复”所选的方程引用样式。
\edef
在定义时求值,而在\def
执行时求值。如果\edef\eqcite#1{}
优先于使用\def\eqcite#1{}
,则对支持格式宏的更改不会产生任何影响,因为\edef
定义中的锁。相反,当使用时\def
,对支持格式宏的更改将影响后续的方程引用。
因此,从哲学上讲,\edef
当人们希望即使支持宏发生变化,某些内容也不会发生变化时,应该使用 。下面的 MWE 试图捕捉当前的选择:使用\def
允许动态\setrefstyle
更改行为,而 则阻止产生任何后续影响。\eqcite
\edef
\setrefstyle
\documentclass{article}
\let\svref\ref
\def\setrefstyle#1{\ifcase#1\relax
\def\refstyle##1{Eq.\,(##1)} \or
\def\refstyle##1{Eqn.\,(##1)} \or
\def\refstyle##1{equation~##1} \else\fi
}
\setrefstyle{0}%
% HERE IS THE CHOICE:
\newcommand\fixeqcite[1][T]{%
\if T#1%
\edef\eqcite##1{\refstyle{\noexpand\ref{##1}}}% <--- TO NOT ALLOW CHANGES
\else%
\def\eqcite##1{\refstyle{\ref{##1}}}%<--- TO ALLOW CHANGES
\fi%
}
\fixeqcite
\begin{document}
\begin{equation}
\label{eq:A}
y=mx+b
\end{equation}
\def\mytest{\smallskip\par
\setrefstyle{0}In \eqcite{eq:A} we see one form of cite\par
\setrefstyle{1}In \eqcite{eq:A} do we see another form of cite?\par
\setrefstyle{2}In \eqcite{eq:A} do we see a third form of cite?\bigskip\par}
Eqcite definition (with edef) is of fixed format, by default.\mytest
But I can let it be redefined (with def) on the fly.\fixeqcite[F]\mytest
\end{document}
答案3
在特殊扩展控件中可以使用with 参数。在v1.3 的第 1997 行\edef
可以找到一个不错的(但相当复杂)示例skeyval-core.tex
\skvrobustdef*\skvpopfunctions#1#2{%
\begingroup
\edef\skv@elt{\skvnoexpandcs{\skvremovescape{#1}@skv@stack}}%
\expandafter\skvifdefTF\skv@elt{%
\expandafter\ifx\skv@elt\@empty
\skv@err{Stack of '\noexpand#1' is empty}\skv@ehd
\fi
}{%
\skv@err{Stack of '\noexpand#1' is undefined}\skv@ehd
}%
\edef\skv@prova{\skvexpandtwice\skv@elt}%
\edef\skv@provb##1##{\endgroup##1\gdef\skvexpandonce\skv@elt}%
\expandafter\skv@provb\skv@prova
\skvgadvanceno#2\m@ne
}
我不确定我是否理解了细节,但肯定\skv@provb
是由定义的\edef
,标准\def
在这里不起作用(因为\skcexpandonce
在里面使用)并且它需要一个参数。
这是 Heiko 所展示的一个更为复杂的案例;如果您愿意,您可能可以在代码中解决这个问题\edef\....##1
,但这样做的努力将非常大。
答案4
嗯,这是我正在寻找的用途之一(它实际上与我在问题中使用的代码相同,但至少它是公开且有用的代码:D)
这l3基准包中的第 420-421 行有一个很好的定义\@@_replicate_kibi_fold:n
(@@
是符号的):
\cs_new:Npx \@@_replicate_kibi_fold:n #1
{ \prg_replicate:nn {1024} {#1} }
正如其名称所示,展开此函数一次可得到其参数的 1024 个副本。这用于避免在用户输入一段非常简单的代码时达到 TeX 内存的限制。