英文:
CALL-ME with gather/take used in a hyper method chain doesn't work
问题
在玩弄方法链和 `CALL-ME`。
以下是我正在使用的玩具类,`CALL-ME` 只是调用给定的值的 Seq 的 `double` 方法。
```raku
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();
首先检查是否可以在方法链中包含 Math
对象 $d
。
这段代码
(1,2,3).map( * + 1 ).$d.map( * +1).say;
输出正确的结果
(5 7 9)
现在将 hyper
放入方法链中
(1,2,3).hyper.map( * + 1 ).$d.map( * + 1 ).say;
这次的输出是
在此处启动的并行迭代的工作程序:
在 block <unit> 中,在 callme.raku 的第 6 行
终止于:
在没有 gather 的情况下 take
在 callme.raku 的第 6 行中的 block
其中第 6 行是 take
行。
我可以通过将 CALL-ME
替换为另一个 map
调用来解决此问题(如下所示),但这引发了一个问题,为什么 map
可以正常工作,而 CALL-ME
不能呢?
(1,2,3).hyper.map( * + 1 ).map( -> $v { $d.double($v) } ).map( * +1).say;
我有遗漏什么吗?
[编辑] 根据 Rawley 的回复更新。
假设我创建一个更大的类,其中还包括一个 CALL-ME
。理想情况下,我希望方法链在串行和并发工作流程中都能以最佳方式运行,而用户不必跳过太多步骤。
如果我保留 CALL-ME
中的 gather
/take
,则在串行上下文中使用时会出现惰性执行,但在使用 hyper
时会完全中断。
或者,删除 CALL-ME
中的 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) } ;
}
}
}
<details>
<summary>英文:</summary>
Been playing with method chaining and `CALL-ME`
Below is a toy class I'm using to play with. The `CALL-ME` just invokes the `double` method for the Seq of values it gets given.
```raku
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();
First check that it is possible to include the Math
object, $d
, in a method chain.
This code
(1,2,3).map( * + 1 ).$d.map( * +1).say;
outputs the correct result
(5 7 9)
Now put hyper
into the method chain
(1,2,3).hyper.map( * + 1 ).$d.map( * + 1 ).say;
Output this time is
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
where line 6 is the take
line.
I can work around the issue by replacing the CALL-ME
with another call to map
(as below), but that leaves the question as to why map
can do-the-right-thing, but CALL-ME
cannot?
(1,2,3).hyper.map( * + 1 ).map( -> $v { $d.double($v) } ).map( * +1).say;
Have I missed something?
[EDIT] Update following reply from Rawley.
Say I create a larger class that also includes a CALL-ME
. Ideally I'd like the method chaining to run optimally in both a serial and concurrent workflow without the user having to jump through too many hoops.
If I leave the gather
/take
in the CALL-ME
I get lazy execution when used in a serial context, but it breaks completely when hyper
is used.
Alternatively, removing the gather
/take
means I have a CALL-ME
that works in both a serial & hyper context. The downside is the serial use-case ends up running in eager mode.
Is there a way for CALL-ME
to have it both ways by testing the context it is running in?
Something like the hypothetical is-hyper-active
below
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) } ;
}
}
}
答案1
得分: 6
Hyper
与传统的 Seq
有很大的不同,使用 gather
和 take
可能不会起作用,因为 Hyper
是异步的。相反,您可以从您的 CALL-ME
中删除 gather
和 take
,并简单地返回映射的结果来使其工作:
class Math does Callable {
method CALL-ME(Iterable:D $i) {
$i.map: -> $t { self.double($t) };
}
method double($x) { return $x * 2}
}
现在你应该看到:
(1,2,3).hyper.map( * + 1 ).$d.map( * + 1 ).say;
可以工作。
个人而言,我避免使用 gather
和 take
,更倾向于只使用方法和函数来构建我的 Seq
。此外,在不返回值的函数中省略 return
更符合惯用法。
英文:
Hyper
is a lot different from traditional Seq
, using gather
and take
most likely won't work because of the asynchronicity of Hyper
. Instead you can drop the gather
and take
from your CALL-ME
and simply return the result of the map to make this work:
class Math does Callable {
method CALL-ME(Iterable:D $i) {
$i.map: -> $t { self.double($t) };
}
method double($x) { return $x * 2}
}
Now you should see that:
(1,2,3).hyper.map( * + 1 ).$d.map( * + 1 ).say;
works.
Personally, I avoid gather
and take
and prefer to just use methods and functions to construct my Seq
's. Also it's a little more idiomatic to omit the return
on functions that don't return in multiple places.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论