Raku能否保证在编译时模式匹配是穷尽的?

5

考虑以下玩具代码:

my $age-check = do given 18 { 
    when $_ > 18 { 'old enough' }
    when $_ < 18 { 'too young'  }
};

say "The user is $age-check"  # OUTPUT: «The user is False»

该代码存在一个 bug(不处理输入恰好为 18 的情况),导致运行时错误。有没有办法通过要求 given 块穷尽匹配来在编译时捕获此错误?似乎可以使用 CHECK 阶段或类似的东西来要求匹配是穷尽的,但我不太确定该如何做到。
(我知道你可以通过抛出错误的 default 情况更早地在运行时捕获 bug,但这不是我要问的。如果 Raku 没有办法在编译时强制执行穷尽匹配,那对该语言来说并不是一个大问题,但这可以是一个有用的功能。)
1个回答

6

虽然在 RakuAST 出现后通过修改 given 语句编写模块来强制执行这些规则是可能的,但这将非常棘手,而且只有对于基本的数值操作才是可行的。

给定语句(given)和情形语句(when)的语义基本上是:

given $foo {         # topicalize $foo
    when $bar1 { … } #   if    $foo ~~ $bar1
    when $bar2 { … } #   elsif $foo ~~ $bar2
    when $bar3 { … } #   elsif $foo ~~ $bar3
    default    { … } #   else 
}

如果您的条件十分复杂,例如 .is-prime* %% 2,甚至是不确定性的(与可变对象进行智能匹配),那么要知道确切条件将会非常困难或不可能。

如果您想对某些条件子集强制执行此级别的严格行为,您可以尝试类似以下的解决方法:

sub is-exhaustive(@conditions) { 
   ... # complex algorithm to determine that the conditions are exhaustive
}

my %foo = 
  less-than-eighteen => *  < 18,
  more-than-eighteen => *  > 18,
  exactly-eighteen   => * == 18;

CHECK die unless is-exhaustive %foo.values;

given $bar {
  when %foo<less-than-eighteen> { ... }
  when %foo<more-than-eighteen> { ... }
  when %foo<exactly-eighteen>   { ... }
}

我猜你们两个在谈论的是(自动)生成测试用例。我很难看出你们如何避免使生成器特定于这里涵盖的表达式。比如说,如果你年满21岁,你就可以喝酒... - BogdanBiv
如果你年满21岁,你就可以喝酒... 作为自动化,你可以编写一个程序来查看源代码并找到字面量(例如数字),然后从中生成随机输入(模糊输入生成器)。无论如何,即使对于人类来说,也不可能确定我们是否已经进行了全面的测试或者还有更多需要做的! - BogdanBiv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接