首页 > 解决方案 > Perl 6 中的“P6opaque, Str”与简单的“Str”类型

问题描述

这是我之前的问题的后续。

我终于能够在这里重现错误:

my @recentList = prompt("Get recentList: e.g. 1 2 3: ").words || (2,4,6);    
say "the list is: ", @recentList;    
for @recentList -> $x {
    say "one element is:  ", $x;
    say "element type is: ", $x.WHAT;
    say "test (1,2,3).tail(\"2\") : ", (1,2,3).tail("2");
    say ( (10.rand.Int xx 10) xx 15 ).map: { @($_.tail($x)); };
}

只要我使用默认列表,只需在提示符处按回车键而不输入任何内容,结果就可以了。但是如果我输入一个数字,它会给出这个错误:

Get recentList: e.g. 1 2 3: 2
the list is: [2]
one element is:  2
element type is: (Str)
test (1,2,3).tail("2") : (2 3)
This type cannot unbox to a native integer: P6opaque, Str
  in block  at intType.p6 line 9
  in block <unit> at intType.p6 line 5

如果 tail("2") 有效,为什么 tail($x) 会失败?此外,在我的原始代码中,tail($x.Int) 不会更正问题,但它确实在这里。

标签: stringinttailraku

解决方案


这充其量只是一个答案。迄今为止,解决这个问题的尝试失败了。我可能只是在杂草丛中徘徊。但我会公布我所拥有的。如果不出意外,也许它可以提醒您以下前三个步骤是明智的;此后,我通过深入研究源代码来赌我前进的能力,而我可能会通过直接调试第三步中讨论的编译器来取得更快和更可靠的进展。


好的,第一步是MRE。你提供的是一个完全是 R 和足够 M 的 E。:)


第 2 步是增加 M(高尔夫)。我把它归结为:

Any.tail('0');    # OK
Any.tail('1');    # BOOM

请注意,它可以是实际值:

1.tail('1');      # BOOM
(1..2).tail('1'); # BOOM

但有些价值观是有效的:

(1,2).tail('1');  # OK

步骤#3 可能应该按照使用Rakudo Perl 6 的代码中say的说明来跟踪编译器的执行,例如通过在其源代码中粘贴s 并重新编译它。

您可能还想尝试App::MoarVM::Debug。(我没有。)

使用这些方法,您将有能力以绝对精确的方式跟踪编译器对您抛出的任何代码所做的事情。我建议你这样做,即使我没有这样做。也许你能弄清楚我哪里出错了。


在下文中,我通过直接探索 Rakudo 编译器的源代码来跟踪这个问题。

Rakudo 源中搜索“方法尾”得到 4 个匹配项。对于我的高尔夫来说,匹配方法是core/AnyIterableMethods.pm6.

tail参数$n显然不是 aCallable所以继续我们探索的相关线路是Rakudo::Iterator.LastNValues(self.iterator,$n,'tail')

对此的搜索导致在 中使用此方法core/Iterator.pm6

这反过来又调用了这个.new例程

这三行

nqp::if(
  n <= 0,                 # must be HLL comparison
  Rakudo::Iterator.Empty, # negative is just nothing

解释为什么'0'有效。<=运算符在进行数值比较之前将其操作数强制为数值。所以'0'强制到0,条件是True,结果是Rakudo::Iterator.Empty,并且Any.tail('0')产量()和不抱怨。

紧跟以上三行的代码nqp::if. 它以 结束nqp::create(self)!SET-SELF(iterator,n,f)

这反过来又调用了!SET-SELF例程,该例程具有以下行:

($!lastn := nqp::setelems(nqp::list, $!size = size)),

size哪个尝试分配'1'$!size. 但是$!size被声明为

has int $!size;

答对了。


或者是吗?我不知道我是否真的正确地追踪了问题。我只是在 github 存储库中挖掘代码,而不是实际运行编译器的检测版本并跟踪其执行,正如在尝试找出您遇到的问题的明智步骤 #3 中所讨论的那样。

更糟糕的是,当我运行一个编译器时,它是一个旧的,而我正在探索的代码是master......


为什么这行得通?

(*,*).tail('1') # OK

这个的代码路径大概就是这个方法。该参数$n不是 aCallable所以代码路径将通过在行中使用的路径运行$n

              nqp::unless(
                nqp::istype($n,Whatever) || $n == Inf,
                $iterator.skip-at-least(nqp::elems($!reified) - $n.Int)

$n == Inf应该问题不大。将==强制其操作数为数字,这应该照顾$nbeing '1'

nqp::elems($!reified) - $n.Int应该也不成问题。

nqp ops 文档显示nqp::elems始终返回int. 所以这归结为int - Int应该起作用的。

唔。

这些行的责备表明,最后一行中的the.Int仅在 3 个月前添加

所以,抓住稻草,如果一个人尝试会发生什么:

(my int $foo = 1) - '1' # OK

不,这不是问题。

看来这条线索已经变冷了,或者更确切地说,我已经偏离了实际的执行路径。

我会发布我所拥有的。也许其他人可以从这里拿走,或者我会在一三天内再去一次……


推荐阅读