Perl 6中`* > 20 && * %% 5`用于grep为何结果异常?
Perl 6中WhateverCode与逻辑运算符结合的陷阱解析
这是个非常典型的Perl 6 WhateverCode与逻辑运算符搭配时的坑,我来给你拆解清楚背后的逻辑:
为什么你的两种写法会得到异常结果?
当你写 * > 20 && * %% 5 时,Perl 6会把它解析成 (* > 20) && (* %% 5)——也就是两个独立的单参数WhateverCode用逻辑与连接。但这里有个关键的Perl 6规则:任何非空的Callable(包括WhateverCode)在布尔上下文中都会被判定为True。
所以:
(* > 20)作为一个合法的Callable,本身就是True,因此整个&&表达式会直接返回第二个WhateverCode* %% 5。这就导致你的grep实际上只筛选了能被5整除的元素,完全忽略了“大于20”的条件,和你看到的(15 20 25 30 35)结果完全吻合。- 同理,
* %% 5 && * > 20会因为第一个Callable* %%5是True,直接返回* >20,所以grep只筛选大于20的元素,这也解释了为什么37会被选中(它大于20,但不能被5整除)。
正确的写法有哪些?
你测试里的几种正确写法都踩中了要点:确保两个条件都作用于同一个元素:
- 显式代码块:
{ $_ > 20 && $_ %% 5 }
这里$_明确绑定到grep传递的每个元素,两个条件都针对同一个值判断,逻辑清晰且结果正确。 - 使用Junction函数
all():all(* > 20, * %% 5)all()是Perl 6里组合“与”条件的惯用方式,它会把多个WhateverCode打包成一个整体,要求每个元素同时满足所有条件。 - 显式Lambda:
-> $a { $a > 20 && $a %% 5 }或-> $a { all($a > 20, $a %% 5) }
显式声明参数$a,强制两个条件都作用于同一个参数,从根源上避免了WhateverCode的绑定歧义。
总结
记住这个规则:不要直接用逻辑运算符(&&/||)连接多个WhateverCode,它们不会组合成针对同一参数的条件,反而会因为Callable的布尔特性短路,只返回其中一个条件。如果要组合多条件,优先用all()/any()这类Junction函数,或者显式的代码块、Lambda。
内容的提问来源于stack exchange,提问作者chenyf
相关产品推荐
相关产品推荐

