在最新的 CTAN 更新中,\bool_if:n(TF) 已贪婪的:...因此,任何仍然假设 \bool_if:n(TF) 进行惰性求值的代码都需要进行调整。
\bool_if:n(TF) 贪婪是什么意思?在这种情况下,惰性求值是什么意思?
我是否可以认为这\bool_if:NT \l__variable_bool
不会受到影响?
答案1
布尔表达式的“贪婪”评估意味着每个子表达式都会被评估,并且只有在此之后完整的布尔表达式才会返回其值。
当仅评估决定表达式真假所必需的部分时,评估就是“懒惰的”。
在该expl3
语言中,可以使用逻辑运算符“and” &&
、“or”||
或“not”!
以及谓词和括号。
自 的上次更新以来expl3
,出于实现原因,用作 的第一个参数的此类布尔表达式\bool_if:nTF
需要进行贪婪求值。具体而言,每个子表达式都需要返回一个布尔值。
但是,expl3
还通过特殊功能提供了惰性求值。
一个很重要的例子就是unicode-math
更新后出现的那个问题,请参见TL 2017 更新后,unicode-math 编译失败
当前代码(待修复)unicode-math
有
\bool_if:nTF { \tl_if_single_p:n {##1} && \token_if_cs_p:N ##1 }
{ \seq_put_right:Nn \l_@@_cmd_range_seq {##1} }
{ \seq_put_right:Nn \l_@@_char_range_seq {##1} }
如果参数是单个标记,则第一个子表达式返回 true;对于惰性求值,如果返回 false,则无需检查第二部分即可得出条件为 false 的结论。对于贪婪求值,当第一部分返回 false 时,也会检查第二部分。
函数的目的是区分range
选项中关键字的值是否\setmainfont
由单个标记(即控制序列)组成。发生的事情是range=`\+
没有通过测试\tl_if_single_p:n
,因此没有尝试第二个条件;但是,在贪婪评估的情况下,仍然执行了第二个测试,导致错误,因为`\+
不是有效的输入\token_if_cs_p:N
。
修复方法是使用惰性求值:
\bool_lazy_and:nnTF { \tl_if_single_p:n {##1} } { \token_if_cs_p:N ##1 }
{ \seq_put_right:Nn \l_@@_cmd_range_seq {##1} }
{ \seq_put_right:Nn \l_@@_char_range_seq {##1} }
其作用与之前相同。
“惰性”函数的lazy
名称中包含:
\bool_lazy_all:nTF
\bool_lazy_any:nTF
\bool_lazy_and:nnTF
\bool_lazy_or:nnTF
前两个需要将任意数量的条件表达式作为第一个参数,每个条件表达式都用括号括起来,因此
\bool_lazy_all:nTF { {<cond-1>} {<cond-2>} ... { <cond-n> } }
{ <true code> }
{ <false code> }
如果全部条件返回 true,但一旦一个条件返回 false,就会停止评估;类似地
\bool_lazy_any:nTF { {<cond-1>} {<cond-2>} ... { <cond-n> } }
{ <true code> }
{ <false code> }
如果任何条件返回 true ,并且一旦返回 true 就会停止。
另外两个接收两个布尔表达式作为其第一个参数,并且是针对最常见情况的精简版本。
显然,这一变化不会影响\bool_if:NTF
,因为这只会检查一个条件。然而,还有另一个与条件相关的变化:类似于
\bool_if:NTF \foo { <true> } { <false> }
当不是条件时,会跟随错误分支\foo
。这种情况不会再发生(这是中断的原因mhchem
)。
曾经有人想过,可以执行惰性求值,但结果却发现这很困难,难以管理,因此只针对“and”和“or”等简单情况引入了惰性求值函数。这发生在编写\bool_if:nTF
代码之后。unicode-math