expl3
提供了几个 do/while/repeat 循环,但我无法找到尽早打破此类循环的方法。
我想要的是类似的东西(用 C 风格的代码)
while (true) {
if (<condition_1>)
break;
<some code>
if (<condition_2>)
break;
<some other code>
...
if (<condition_n>)
break;
<even more code>
}
我当然可以为此定义自己的宏,但是有没有办法使用expl3
模块已经提供的函数?或者,expl3
这方面的惯用解决方案是什么?\prg_break_point:
看起来很有希望,但我不知道应该如何使用它。
答案1
概念证明,无需认真对待
你可以调皮一下,利用你想使用的函数的实现细节来更快地破坏它。例如,take 的\bool_do_while:Nn
定义如下:
\cs_new:Npn \bool_do_while:Nn #1#2
{ #2 \bool_if:NT #1 { \bool_do_while:Nn #1 {#2} } }
您提供的代码在 之前执行\bool_if:NT
。您可以定义一些宏,将其反转\bool_if:NT
为\bool_if:NF
然后返回相反的(或者一个消耗一切并一举结束一切的宏)。例如(我希望这个名字足够有启发性 ;-)
\cs_new:Npn \__siracusa_DONT_DO_THIS:w #1 \bool_if:NT { \bool_if:NF }
那么你可以像这样使用:
\int_new:N \l_siracusa_tmp_int
\bool_do_while:Nn \c_true_bool
{
\int_incr:N \l_siracusa_tmp_int
% if (<condition>)
\int_compare:nNnT { \l_siracusa_tmp_int } = { 6 }
{ \__siracusa_DONT_DO_THIS:w } % break;
% <some code>
Hello~\int_use:N \l_siracusa_tmp_int \par
}
您可以在循环主体中设置任意多个条件,并且只要\bool_if:NT
代码主体中没有出现(至少没有括号)就可以从任何地方发出中断代码。例如,可以通过在循环主体末尾添加标记来使其更加健壮。
然而,这只适用于\bool_do_while:Nn
,因为它依赖于宏的定义方式,并且不言而喻,如果实现中发生任何变化(这是可能的),代码就会严重崩溃。
答案2
需要说明的是,这是我目前使用的方法:
\cs_new_protected:Npn \__foo_goto_loop_end:w #1 \__foo_loop_end: { }
\cs_new_protected:Npn \__foo_loop_end: { }
\bool_set_true:N \l_tmpa_bool
\int_set:Nn \l_tmpa_int { 1 }
\bool_do_while:Nn \l_tmpa_bool {
\int_compare:nNnT \l_tmpa_int > 9 {
\bool_set_false:N \l_tmpa_bool
\__foo_goto_loop_end:w
}
% Other conditions ...
\int_compare:nNnT 0 = 1 {
\bool_set_false:N \l_tmpa_bool
\__foo_goto_loop_end:w
}
\iow_term:x { iteration~\int_eval:n \l_tmpa_int }
\int_gincr:N \l_tmpa_int
\__foo_loop_end:
}
代码跳过的思路类似于Phelype Oleinik 的回答,但它并没有真正打破循环,它只是跳到循环末尾,跳过循环体的所有剩余代码。因此,这不依赖于循环宏的内部定义,因此适用于所有循环变体。