前面介绍的内容中,控制序列都是按顺序逐个执行的,本文将介绍如何条件处理的相关概念。
一、概念
1.1 条件处理
在 LaTeX3 中条件处理(Conditional Processing)被定义为执行一系列测试的东西, 它可能涉及到赋值或调用其它函数。处理这个输入之后,返回一个状态(State)。 这个返回的状态可能是
⟨true⟩
或
⟨false⟩
。
1.2 断言与条件句
LaTeX3 有三个条件流处理(Conditional Flow Processing)的概念:(其中有两种是基于条件处理返回的状态的条件流处理)
断言(Predicate)
是一种返回特殊类型的布尔值(Boolean Value)的函数,所有这种类型的函数都是可展开的,并且名字的描述部分以_p 结尾;
分支条件(Branching Conditional)
先执行测试,然后根据测试结果执行不同分支代码的函数。这些类型的函数被称为条件句(Conditional),条件句的参数说明符里必须有
T
、
F
或
TF
,表示它只有真分支、假分支或同时有真假分支。条件为真,则执行真分支,条件为假,则执行假分支(对果对应分支不存在,则无输出);
原语条件句
这是条件句的第三个变种,它是plain TeX 和LaTeX 2ε 里原始的概念。但不鼓励在 expl3 中使用它们(尽管仍在低级别的定义中使用),因为它们更脆 弱(Fragile)。
二、用法
条件流处理相关的函数由模块
l3prg
归档,下面介绍一些基本的用法。
2.1 条件句与断言示例
LaTeX3 内部预定义一系列用于条件处理的函数,先看以下示例:
\ documentclass {article} \ usepackage {ctex} \ begin {document} \ ExplSyntaxOn % \prg_do_nothing: 一个不做任何事的可展开函数 \ cs _new:Nn \ my _func_a: { \ prg _do_nothing: } % 有真假分支的条件句:检测控制序列是否已定义 \ cs _if_exist:NTF \ my _func_a: { 控制序列已定义; } { 控制序列未定义; } % 特例:以下将测试为假 \
cs _if_exist:NTF \ relax { 1 } { 0 } \ par % 只有假分支的条件句:检测控制序列是否可用于定义 \ cs _if_free:NF \ my _func_a: { 控制序列不可用于自由定义 } % 断言:它将返回真(不会输出,但在日志里有痕迹) \ cs _if_exist_p:N \ my _func_a: \ ExplSyntaxOff \ end {document}
img
条件句的使用示例
代码解释:
因为
\my_func_a:
已定义,所以
\cs_if_exist:NTF
的测试结果为真,所以输出真分支
{ 控制序列已定义; }
;
\cs_if_exist:NTF
对
\relax
测试会结果为假,这是特例;
\cs_if_free:NF
只有假分支,此次测试结果为假(因为已有定义,不能用于自由定义),所以执行假分支;
\cs_if_exist_p:N
是个断言函数,它结果会返回真;正常不应这样使用,它应当放在其它函数中。
2.2 定义条件句与断言
LaTeX3 提供
\prg_new_conditional:Nnn
等函数,用于定义条件流处理函数。
\ documentclass {article} \ usepackage {ctex} \ begin {document} \ ExplSyntaxOn % 定义条件句,函数名不直接带 p,T,F 字样 % 而是由一个 n 参数指定(逗号分隔) % 这里的 p 是 “_p” 断言, 和 cs_new:Npn 里的 p 参数意义不一样 \ prg _new_conditional:Nnn \ my _if_ge_zero:n { p , T , F, TF } { % 函数体内只需要返回逻辑真与假即可 % 其余由 \prg_new_conditional:Nnn 函数处理 \ int _compare:nNnTF { #1 } > { 0 } { \ prg _return_true: } { \ prg _return_false: } } % 此时定义了如下四个函数变体 \ my _if_ge_zero:nTF { 1 } { Y } { N } \ par \ my _if_ge_zero:nT { 2 } { 大于零 } \ par \ my _if_ge_zero:nF { 3 } { 小于零 } \ par \ my _if_ge_zero_p:n { 4 } \ par \ ExplSyntaxOff \ end {document}
img
条件句的定义示例
代码解释:
\prg_return_true:
和
\prg_return_false:
“返回” 函数定义了条件语句的一个逻辑状态;当它们在这样的条件的代码中出现多次时,必须确认条件句的运行过程中恰好一次地展开了这两个函数中的任意一个;
\my_if_ge_zero:nF { 3 } { 小于零 }
这句因为条件为真,但没有真分支,所以没有任何输出。
2.3 条件处理函数的变体
与普通函数定义变体的方式不一样,条件处理函数有专门的函数生成变体。请看如下示例:
\ documentclass {article} \ usepackage {ctex} \ begin {document} \ ExplSyntaxOn \ prg _new_conditional:Nnn \ my _if_ge_zero:n { p , T , F, TF } { \ int _compare:nNnTF { #1 } > { 0 } { \ prg _return_true: } { \ prg _return_false: } } % 为 T, TF 条件句定义了 V 变体 \ prg _generate_conditional_variant:Nnn \ my _if_ge_zero:n { V } { T, TF } \ int _set:Nn \ l _tmpa_int { 1 + 2 } % 只有这两个条件句有变体 \ my _if_ge_zero:VTF \ l _tmpa_int { Y } { N } \ par \ my _if_ge_zero:VT \ l _tmpa_int { 大于零 } \ par % 下面两个变体是没有定义 % \my_if_ge_zero:VF \l_tmpa_int { 小于零 } \par % \my_if_ge_zero_p:V \l_tmpa_int \par \ ExplSyntaxOff \ end {document}
这里的变体是针对 Nn 参数,不是针对 pTF 的。
2.4 原语条件句
LaTeX3 不推荐使用原语条件句,这里只举个例子,供有兴趣的用户自行研究:
\ documentclass {article} \ usepackage {ctex} \ begin {document} \ ExplSyntaxOn \ bool _set:Nn \ l _tmpa_bool { \ int _compare_p:n { 2 = 4 } } % \if_bool:N ... \else: ... \fi: \ if _bool:N \ l _tmpa_bool % 真分支 布尔值为真 \ par \ else : % 假分支 布尔值为假 \ par \ fi : % \if_predicate:w ... \else: ... \fi: \ if _predicate:w % 断言 \ int _compare_p:n { 2 = 4 } % 真分支 布尔值为真 \ par \ else : % 假分支 布尔值为假 \ par \ fi : \ ExplSyntaxOff \ end {document}
原语条件句的示例
选自:
https://zhuanlan.zhihu.com/p/11864674140
成为 LaTeX 会员,尽享精致科研!
开通 LaTeX VIP 地址:
https://www.latexstudio.net/index/recharge/choice.html