一直在玩方法链和CALL-ME
下面是我用来玩的一个玩具类。它CALL-ME只是调用double给定值的 Seq 方法。
class Math does Callable
{
method CALL-ME(Iterable:D $i)
{
gather {
$i.map: -> $v { take self.double($v) } ;
}
}
method double($x) { return $x * 2}
}
my $d = Math.new();
Run Code Online (Sandbox Code Playgroud)
首先检查是否可以将Math对象包含$d在方法链中。
这段代码
(1,2,3).map( * + 1 ).$d.map( * +1).say;
Run Code Online (Sandbox Code Playgroud)
输出正确的结果
(5 7 9)
Run Code Online (Sandbox Code Playgroud)
现在放入hyper方法链中
(1,2,3).hyper.map( * + 1 ).$d.map( * + 1 ).say;
Run Code Online (Sandbox Code Playgroud)
这次的输出是
A worker in a parallel iteration (hyper or race) initiated here:
in block <unit> at callme.raku line 6
Died at:
take without gather
in block at callme.raku line 6
Run Code Online (Sandbox Code Playgroud)
其中第 6 行是该take行。
CALL-ME我可以通过将 替换为另一个调用(如下所示)来解决这个问题map,但这留下了一个问题:为什么map可以做正确的事情,但CALL-ME不能?
(1,2,3).hyper.map( * + 1 ).map( -> $v { $d.double($v) } ).map( * +1).say;
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
[编辑]更新以下来自罗利的回复。
假设我创建了一个更大的类,其中还包括一个CALL-ME. 理想情况下,我希望方法链接能够在串行和并发工作流程中以最佳方式运行,而用户不必跳过太多的障碍。
如果我将gather/take保留CALL-ME在串行上下文中时,我会得到延迟执行,但在hyper使用时它会完全中断。
或者,删除gather/take意味着我有一个CALL-ME可以在串行和超上下文中工作的。缺点是串行用例最终以急切模式运行。
有没有办法CALL-ME通过测试它运行的上下文来实现这两种方式?
is-hyper-active就像下面的假设一样
method CALL-ME(Iterable:D $i)
{
if is-hyper-active {
$i.map: -> $v { take self.double($v)
} else {
gather {
$i.map: -> $v { take self.double($v) } ;
}
}
}
Run Code Online (Sandbox Code Playgroud)
Hyper与传统的有很大不同Seq,使用gather并且take很可能由于 的异步性而无法工作Hyper。相反,您可以从您的中删除gatherand并简单地返回地图的结果以使其工作:takeCALL-ME
class Math does Callable {
method CALL-ME(Iterable:D $i) {
$i.map: -> $t { self.double($t) };
}
method double($x) { return $x * 2}
}
Run Code Online (Sandbox Code Playgroud)
现在你应该看到:
(1,2,3).hyper.map( * + 1 ).$d.map( * + 1 ).say;
Run Code Online (Sandbox Code Playgroud)
作品。
就我个人而言,我避免gather并且take更喜欢仅使用方法和函数来构造我Seq的。return另外,省略在多个地方不返回的 on 函数也更惯用。
| 归档时间: |
|
| 查看次数: |
157 次 |
| 最近记录: |