重新打开环境以向其中添加更多命令/子环境

重新打开环境以向其中添加更多命令/子环境

我想知道您是否可以“重新打开”一个环境来扩展其定义,类似于在 Ruby 等编程语言中您可以在代码中的任何位置重新打开一个类/模块并扩展其定义。

例如,假设你的文档中有这样的部分:

\newenvironment{myenv}{
  \newcommand\a{}
}{}

然后在文档的后面执行以下操作:

\reopenenvironment{myenv}{
  \newcommand\b{}
}{}

这样最终的结果就是这样的:

\newenvironment{myenv}{
  \newcommand\a{}
}{}

\reopenenvironment{myenv}{
  \newcommand\b{}
}{}

其功能应等同于:

\newenvironment{myenv}{
  \newcommand\a{}
  \newcommand\b{}
}{}

想知道 Latex 中是否存在类似的东西。理由是假设您有一个包含一些通用定义的类。您可能希望多次重复使用各种格式的特定图表,但没有必要将其添加到类定义中。相反,您只需在文档中内联定义它并在需要的地方使用它。

这个问题的另一种变体(或可能实现的另一种方法)是向现有命令添加新的条件块。假设我们有\a

\newenvironment{myenv}{
  \newcommand\a[1]{
    \ifthenelse{\equal{##1}{\string foo}}
      {\typeout{foo}}
      {}
  }
}{}

然后您可以在运行时扩展这样的定义:

\reopenenvironment{myenv}{
  \reopencommand\a[1]{
    \ifthenelse{\equal{##1}{\string bar}}
      {\typeout{bar}}
      {}
    \super{}
  }
}{}

这样,您可以在运行时扩展它,以便保留 API:

\begin{myenv}
  \a{foo}
  \a{bar}
\end{myenv}

想知道是否存在类似的东西,或者是否有一种正常的方法来用乳胶实现这一点。

我希望能够执行以下操作:

\begin{athing}{label=baz}
  \stuff
  \stuff
  \stuff
  \stuff
\end{athing}

然后将其用作:

\begin{myenv}
  \a{baz}
\end{myenv}

也许可以通过本地键/值存储来实现这一点。也就是说,

kvstore = {
  foo: athing
  bar: athing
  baz: athing
}

\newcommand\a[1]{
  kvstore[##1]
}

也许这种事情是可能的,如果可能的话,那将是另一种解决方案。

总而言之,我希望能够拥有一个 API:

myapi{somelabela}
myapi{somelabelb}
...

这样就可以在运行时使用更多定义进行扩展。这里概述的 3 种方法只是初步想法,我是 Latex 的新手。非常感谢您的帮助。

答案1

LaTeX3 (expl3) 实际上有一个很好的界面来处理代币列表,它或多或少具有您正在寻找的功能。

编辑:意识到我(之前)的第一个方法并不规范。这个方法更好,也更不老套:

在 LaTeX 中,我怀疑规范方法是使用宏钩子,或者更具体地说\g@addto@macro。这就是\AtBeginDocument工作原理!

\makeatletter
\def\somehook{hello}
\g@addto@macro\somehook{ world}
\somehook %<- prints hello world
\makeatother

该命令实际上会触发您执行时定义的\begin{myenv}宏。因此:\myenv\newenvironment

\makeatletter
\newenvironment{myenv}{hello}{}
\g@addto@macro\myenv{ world}
\begin{myenv}
  !
\end{myenv}
\makeatother

打印hello world!


以下是我不太规范的方法:

不管怎样,你可以用纯 TeX 自己做,或多或少:你可以做的一个“黑客”是

\newenvironment{myenv}{Hello}{}
\let\oldMyenv = \myenv
\def\myenv{\oldMyenv world}
\begin{myenv}
!
\end{myenv}

输出结果Hello world !为 。这可以推广到

\makeatletter
\def\removebs#1{\if#1\@backslashchar\else#1\fi}
\def\macname#1{\expandafter\removebs\string#1}
\def\reopencommand#1#2{
  \def\mname{\macname{#1}}
  \let\oldCommand#1
  \expandafter\gdef\csname \mname\endcsname{\oldCommand #2}
}
\def\hello{hello}
\reopencommand{\hello}{ world}
\hello
\makeatother

相关内容