我非常喜欢使用 LaTeX3 来编写我的 LaTeX 程序,我使用得越多,就越容易使用,我越不想回到 LaTeX2e 甚至纯 TeX!但我时不时地会发现自己需要与 LaTeX2e 交互在编程层面。例如,某些 LaTeX2e 包可能设置了条件,我想在用 LaTeX3 编写的包中测试这些条件。我可以使用 LaTeX2e 方法执行此操作:
\ifcondition
<stuff>
\else
<other stuff>
\fi
\expandafter
但我不喜欢这样,部分原因是如果我想确保\else
和不会干扰内部代码,我必须记住担心s \fi
。所以我宁愿坚持使用 LaTeX3 语法。
我目前的上述代码是:
\prg_new_conditional:Npnn \latex_if:N #1 {p,T,F,TF}
{
\if_meaning:w #1 \iftrue
\prg_return_true: \else: \prg_return_false: \fi:
}
这是一个合理的方法吗,或者有更好的方法吗?
同样,(我希望我能在这里回答两个问题,因为它们是如此密切相关)我应该如何与 LaTeX2e 宏交互?假设一个包定义了一个宏\def\something{This is some text we'll save for later.}
,我想使用 LaTeX3 来处理它。我认为我应该将其视为一个标记列表(tl
),对吗?这样做有什么陷阱吗?
答案1
\latex_if:NTF \ifmmode
当使用时,您的代码将返回 false ,\ifmmode
因为不是与 相同\iftrue
,即使我们处于数学模式。它仅适用于已定义的条件,例如\if@minipage
,因为这是由 引入的\newif
,所以它要么是 ,\iftrue
要么是\iffalse
。
你的函数应该对定义的条件和原始条件都以相同的方式工作,以获得最大的灵活性;你可能需要这样做
\bool_if:nTF { \latex_if_p:n {@minipage} || \latex_if_p:n {mmode} }
{true code}
{false code}
(这不太可能,但是表明了这个想法)。
我会采取不同的做法:
\prg_new_conditional:Npnn \latex_if:n #1 {p,T,F,TF}
{
\use:c{if#1} \prg_return_true: \else: \prg_return_false: \fi:
}
用作
\latex_if:nTF {mmode} {code for math mode} {code for non math mode}
如果你愿意,你可以这样做
\prg_new_conditional:Npnn \latex_if:N #1 {p,T,F,TF}
{
#1 \prg_return_true: \else: \prg_return_false: \fi:
}
但这有一个缺点,就是要求\makeatletter
何时\if@minipage
进行测试。
答案2
对于你的第一个问题,我会说答案是肯定的,这是正确的方法,而且很简洁。但是,如果我们假设该论证始终是 2e 条件,那么定义可以变得更简单:
\prg_new_conditional:Npnn \latex_if:N #1 {p,T,F,TF}
{
#1 \prg_return_true: \else: \prg_return_false: \fi:
}
感谢@egreg 指出这一点。
它还允许您在谓词中使用那些 2e 布尔值,例如,
\bool_if:nTF
{
\latex_if_p:N \if@minipage ||
\latex_if_p:N \ifinner ||
...
但当然\latex_if_p:N \ifinner
可以直接使用 expl3 equiv,即\mode_if_inner_p:
。
我不太热衷于这样的建议(如评论中所建议的):
\bool_if:nTF
{
\if@minipage 1 \else 0 \fi || %compatible to LaTeX2e
\ifinner 1 \else 0 \fi || %compatible to LaTeX2e
为什么?很简单,它公开了 expl3 布尔实现的内部实现细节,这是一个不好。如果它真的应该返回\prg_return_true:
,但即使如此... :-)
至于第二个问题,答案是:视情况而定。显然,任何本质上是“标记列表”的 2e 宏都应该按此方式操作,因此,是的,它将是一个“tl”,并且不应该存在任何陷阱。
当然,您可以提供一个明确的接口,在完成后将其转换为 l3 名称并转换回 2e 名称,但在我看来,在这种情况下,您只会增加犯错的几率(以及额外的处理时间)。
更复杂的是任何带有参数的宏。
如果你只是想使用它,那么我认为值得考虑在一开始就定义一个符合 expl3 的名称并始终使用它。在这种情况下,代码会更简洁。
如果由于某种原因您需要对其进行操作,那么所有\cs_...
功能都应该可以工作,而对于其余功能则需要根据具体情况进行查看。
以上就是我的想法,也许其他人还有其他想法。