多路比较
— 焉知非鱼多路比较
RFC 25, 作者:Damian Conway。运算符: 多路比较
这个 RFC 最初是在8月4日提出的, 一个月后被冻结。
它描述了一个简单直观的功能, 使代码服从我的意思规则:
if ( 0 <= $x <= 10 ) {
print "digit"
}
二十年前, 不指望能如愿以偿, 这并不是一个很大的惊喜。
现在我们可以称之为"运算符链", 现在它在编程语言中并不常见。人们可以想到很多原因, 其中包括没有把它当作一个重要的功能, 需要打破向后的兼容性, 有时只是没有想到。
然而, 在 Raku 编程语言设计过程中, 各种智者提出自己的想法成为可能。
虽然有人可能会认为这是一个太小的值得努力的功能, 但 Raku 是在 “修复语言, 而不是修复用户"的旗帜下设计的, 因此, 即使是这样的改变也是想要的。
虽然这个功能原本在 Perl 中是缺失的, 但自 v5.32 版本发布后, 它最终得到了这样的逻辑链式支持。
RFC 76, 作者:Damian Conway。内置函数: reduce
这个 RFC 提出了一个内置的 reduce
函数, 灵感来自于 Graham Barr 编写的 List::Utils
模块。
对于那些对诸如 fold
或 reduce
函数式编程感兴趣的人来说, 这个函数很熟悉, 因为它是帮助数据处理的工具之一。
$sum = reduce {$_[0]+$_[1]} 0, @numbers;
$sum = reduce sub{$_[0]+$_[1]}, 0, @numbers;
$sum = reduce ^_+^_, 0, @numbers;
reduce
子例程, 当给定一个要应用的操作和一个值的列表时, 以这种方式将这个操作应用于值:
result0 = init
result1 = f(result0, list[0])
result2 = f(result1, list[1])
...
resultn = f(resultn-1, list[n-1])
然而, 自从 Damian Conway 在8月10日提出了这个 RFC 之后, 一个月后它就被冻结了, 这个子例程演变成了一个更令人兴奋的工具。
在 Raku 中, reduce
还可以:
# Have an identity value as default when there are no items to run on:
say reduce &infix:<+>, []; # OUTPUT: «0»
# Have a method form as well:
say [].reduce(&infix:<+>); # OUTPUT: «0»
# Have operator application order depending on actual operator associativity:
# 1) Define two operators with different associativity
sub infix:<foo>($a, $b) is assoc<right> { "($a, $b)" }
sub infix:<bar>($a, $b) is assoc<left> { "($a, $b)" }
# 2)Observe!
say [foo] 1, 2, 3, 4; # OUTPUT: «(1, (2, (3, 4)))»
say [bar] 1, 2, 3, 4; # OUTPUT: «(((1, 2), 3), 4)»
# Operate on Supply type, which is an thread-safe, asynchronous data stream,
# allowing transforming of a Supply into another supply, which
# reduces all asynchronous values and asynchronously emits result:
my $supply = Supply.from-list(1..5).reduce({$^a + $^b});
$supply.tap(-> $v { say "$v" }); # OUTPUT: «15»
这样一来, 一个看似简单的建议就会影响到语言的多个部分, 让简单的事情变得简单, 让难的事情变得可能。
RFC 193, 作者:Damian Conway。对象:方法代理的核心支持
这个 RFC 最初是在9月4日提出的, 稍后又被冻结了, 这个 RFC 引入了一个方法代理的特殊语法糖的概念。
在面向对象编程中, 代理模式是一种设计模式, 它允许使用一个内部对象来处理对外部对象的调用, 允许它模仿内部对象而不需要显式继承或代码重复。
然而, 在许多语言中, 这种模式的实现需要明确地写出所有的方法:
// Java program to illustrate delegation
class Inner {
// the "delegate" 1
void doWork() {
System.out.println("It worked out!");
}
// the "delegate" 2
void doMoreWork() {
System.out.println("It worked out even better!");
}
}
class Outer {
// the "delegator"
Inner inner = new Inner();
// create the delegate 1
void doWork() {
inner.doWork(); // delegation
}
// create the delegate 2
void doMoreWork() {
inner.doMoreWork(); // delegation
}
}
这种手动方式引入了大量的模板:每个代理的方法都必须明确地写出所有参数和调用代码。
有关的 RFC 建议使用指令 delegation
这样的方式:
use delegation
attr1 => [qw( method1 method2 method3 )],
attr2 => [qw( method4 method5 )],
attr3 => __ALL__,
attr4 => __ALL__,
# etc.
;
这极大地减少了用户需要编写的模板数量!
然而, 随着 Raku 设计获得特性, 编译时行为规范允许改变机器对某些代码的看法, 这种 RFC 的实现最终变得更加优雅:
class Inner {
method doWork {
say 'It worked out!';
}
method doMoreWork {
say 'It worked out even better!';
}
}
class Outer {
has Inner $.i handles <doWork doMoreWork>;
}
多么干净利落的 Raku 方式!
总而言之
在这篇文章中, 我们讨论了三个独立的功能, 这些功能乍一看似乎很小, 但在一天结束时, 你有所有的美丽, 不同部分的语言相互连接在一起玩得很好。
一个概念必然会拉动另一个概念, 你的工具带会随着你的学习变得越来越多功能。
为所有走过漫长而艰辛的道路的人点赞, 他们把各种想法涌现出来, 变成一件件扎扎实实的作品实现, 并在各种情况下帮忙。