\edef 与宏参数的实用应用

\edef 与宏参数的实用应用

好吧,这个想法在我脑子里已经酝酿了一段时间,但还没有结果,所以我在这里问一下。在什么地方有用\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带参数的用法。但是,我正在寻找的是参数位于宏的参数内的情况,该宏在\edefed 时会展开(就像我的例子一样)。我不知道如何写清楚,请随意编辑问题。

答案1

在 TeX Live 2015 中搜索要定义的命令和参数的\edef\xdef(全局变体)并过滤掉可能的误报(当命令由 构造时\csname):

 egrep -r '\\[ex]def\\[a-zA-Z@]+#1' texmf-dist/tex/ | grep -v '\\[ex]def\\csname'

结果是 219 行。

我不想讨论所有的发现,因此我仅限于举几个例子。

\TextOrMathLaTeX 内核的示例( latex.ltx)

最近,\TextOrMathLaTeX 内核添加了宏:

\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 内存的限制。

相关内容