打电话而不打电话给其他候选人? "other candidates" 是什么?是否已耗尽其他候选人名单?那个名单可用吗?

Callwith not calling other candidates? What are "other candidates"? Is it exhausting the list of other candidates? Is that list available?

我正在尝试解决 this issue, which was actually raised by this other Whosebug question related to the different behavior of callwith and samewith。后者的定义似乎很明确,但是 callwith.

就不太清楚了

看看这个例子:

proto how-many(|) {*}

multi sub how-many( Pair $a, Pair $b ) {
    say "Int $a and $b";
    return "There are $a and $b"

}
multi sub how-many( $a, $b ) {
    say "Not int $a and $b";
    my $calling = callwith( 1 => $a, 2 => $b );
    return $calling;
}

say how-many( "little piggie","littler piggie" );

根据文档,callwith 应该调用下一个匹配候选。然而,这是输出:

Not int little piggie and littler piggie
(Any)

所以它正在调用 how-many 的第二个版本,然后调用一个不存在的函数(显然)并返回 Nil,它作为 Any 传递给调用例程。

我也尝试过使用不同的签名,但这也不起作用。文档中的示例显然表明它仅在变量属于同一 class 层次结构时才有效。是这样吗?它可能不是,因为将位置签名更改为 Any $a, Any $b 也不起作用,既不改变声明的顺序。

Above, changing callwith with samewith will obviously work, but I'm trying to understand how callwith works, not make the code above work.

此外,它似乎在 class 层次结构中 向下 ,而不是向上。这个 example in roast,Perl 6 测试套件,有效:

my $tracker = '';
multi d($x)     { $tracker ~= 'Any' ~ $x };
multi d(Int $x) { $tracker ~= 'Int'; callwith($x+1); $tracker ~= 'Int' };
lives-ok { d(3) }, 'can call callwith inside a multi sub';

但是,如果我们更改它以便我们从层次结构的底部使用 callwith,如下所示:

my $tracker = '';
multi d($x)      { $tracker ~= 'Any' ~ callwith( "called-with" => $x) };
multi d(Pair $x) { $tracker ~= "Pair $x" };

say d( 3 );

它失败了

Use of Nil in string context in sub d at rewrite-test-callwith.p6 line 6

这是有意为之的行为吗?

所有 callwithnextwithcallsamenextsame 遍历由原始参数 [=55] 确定的候选集 =].因此,虽然 callwith 可用于替换参数,但它所做的仅此而已。它不会导致要迭代的预先确定的候选人列表发生变化。

考虑这三位候选人:

multi foo(Any $x)  { say "In Any case with $x" }
multi foo(Real $x) { say "In Real case with $x"; callwith($x.Int); }
multi foo(Int $x)  { say "In Int case with $x"; callsame(); }

我们可以使用 .cando 询问哪些候选人申请并传递 Capture。因此:

.say for &foo.cando(\(42));

将产生以下输出:

sub foo (Int $x) { #`(Sub|78402328) ... }
sub foo (Real $x) { #`(Sub|78412816) ... }
sub foo ($x) { #`(Sub|78412968) ... }

因为所有 3 个候选人都匹配。调用 foo(42) 将导致以下输出:

In Int case with 42
In Real case with 42
In Any case with 42

相比之下,有:

.say for &foo.cando(\(4.2));

输出为:

sub foo (Real $x) { #`(Sub|78412816) ... }
sub foo ($x) { #`(Sub|78412968) ... }

并且调用 foo(4.2)callwith 遍历这些候选人:

In Real case with 4.2
In Any case with 4

A callwith 或类似的最一般的候选人不会有任何影响,并将评估为 Nil

虽然这里的例子是多子,这同样适用于包装器和非多方法,它们也遍历预定列表。

最后,还值得一提的是,如果每次都有新的dispatch,那么我举的这个例子最终会变成无限递归。通过遍历预先确定的候选列表,这永远不会发生。

请注意,其中 none 适用于 samewith,它的存在正是为了进行全新的调度。