Wait the light to fall

多路比较

焉知非鱼

多路比较

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 模块。

对于那些对诸如 foldreduce 函数式编程感兴趣的人来说, 这个函数很熟悉, 因为它是帮助数据处理的工具之一。

$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 方式!

总而言之

在这篇文章中, 我们讨论了三个独立的功能, 这些功能乍一看似乎很小, 但在一天结束时, 你有所有的美丽, 不同部分的语言相互连接在一起玩得很好。

一个概念必然会拉动另一个概念, 你的工具带会随着你的学习变得越来越多功能。

为所有走过漫长而艰辛的道路的人点赞, 他们把各种想法涌现出来, 变成一件件扎扎实实的作品实现, 并在各种情况下帮忙。