“P6opaque, Str” 与 Perl 6 中的简单“Str”类型
“P6opaque, Str” vs simple “Str” types in Perl 6
这是 的后续。
我终于能够在此处重现错误:
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)); };
}
只要我使用默认列表,只需在提示符下点击 return 并且不输入任何内容,结果就可以了。但是如果我输入一个数字,它会给出这个错误:
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) 不会纠正问题,但它在这里做到了。
这充其量只是一个 nanswer。这是一个 thus-far 试图解决这个问题的失败尝试。我可能只是在杂草丛中徘徊。但我会发布我所拥有的。如果不出意外,也许它可以作为一个提醒,下面的前三个步骤是明智的;此后,我赌自己有能力通过探索源代码来继续前进,而我可能会按照第三步中讨论的那样直接调试编译器来取得更快、更可靠的进展。
好的,第一步是 MRE。您提供的是一个 E,它完全是 R 并且足够 M。:)
第 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 步可能 应该 遵循 Playing with the code of Rakudo Perl 6 中的说明来跟踪编译器的执行,例如在其源代码中添加 say
s并重新编译它。
您可能还想试试 App::MoarVM::Debug。 (我没有。)
使用这些方法,您将能够绝对精确地跟踪编译器对您输入的任何代码执行的操作。我建议你这样做,即使我没有这样做。也许你能找出我哪里出错了。
在下文中,我通过直接探索 Rakudo 编译器的源代码来跟踪这个问题。
一个search for "method tail" in the Rakudo sources yielded 4 matches. For my golf the matching method is a match in core/AnyIterableMethods.pm6
.
tail
参数 $n
显然不是 Callable
所以继续我们的探索的相关行是 Rakudo::Iterator.LastNValues(self.iterator,$n,'tail')
.
对此进行搜索会在 core/Iterator.pm6
中找到 this method。
这又调用了this .new
routine。
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
的else分支。它以 nqp::create(self)!SET-SELF(iterator,n,f)
.
结束
这又会调用 !SET-SELF
例程,其中包含以下行:
($!lastn := nqp::setelems(nqp::list, $!size = size)),
尝试将 size
(在我们的 BOOM 案例中是 '1'
)分配给 $!size
。但是 $!size
is declared as:
has int $!size;
宾果。
或者是吗?我不知道我是否真的 正确地找到了问题所在。我只是在探索 github 存储库中的代码,实际上并没有 运行 编译器的检测版本并跟踪其执行,正如在试图找出问题的明智步骤 #3 中所讨论的那样你遇到过。
更糟糕的是,当我运行编译器时,它是一个旧编译器,而我正在探索的代码是 master
...
为什么这样做?
(*,*).tail('1') # OK
此代码路径大概是 this method。参数 $n
不是 Callable
,因此代码路径将 运行 通过在以下行中使用 $n
的路径:
nqp::unless(
nqp::istype($n,Whatever) || $n == Inf,
$iterator.skip-at-least(nqp::elems($!reified) - $n.Int)
$n == Inf
应该不是问题。 ==
会将其操作数强制转换为数字,并且应该注意 $n
为 '1'
.
nqp::elems($!reified) - $n.Int
应该也不是问题。
nqp ops 文档显示 nqp::elems
always returns an int
。所以这归结为一个应该工作的int - Int
。
嗯。
A blame of these lines shows that the .Int
in the last line was only added 3 months ago.
所以,抓住救命稻草,如果尝试会发生什么:
(my int $foo = 1) - '1' # OK
不,这不是问题。
这条路似乎变冷了,或者我已经偏离了实际的执行路径。
我会发布我得到的东西。也许其他人可以从这里拿起它,或者我会在一三天内再去一次...
这是
我终于能够在此处重现错误:
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)); };
}
只要我使用默认列表,只需在提示符下点击 return 并且不输入任何内容,结果就可以了。但是如果我输入一个数字,它会给出这个错误:
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) 不会纠正问题,但它在这里做到了。
这充其量只是一个 nanswer。这是一个 thus-far 试图解决这个问题的失败尝试。我可能只是在杂草丛中徘徊。但我会发布我所拥有的。如果不出意外,也许它可以作为一个提醒,下面的前三个步骤是明智的;此后,我赌自己有能力通过探索源代码来继续前进,而我可能会按照第三步中讨论的那样直接调试编译器来取得更快、更可靠的进展。
好的,第一步是 MRE。您提供的是一个 E,它完全是 R 并且足够 M。:)
第 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 步可能 应该 遵循 Playing with the code of Rakudo Perl 6 中的说明来跟踪编译器的执行,例如在其源代码中添加 say
s并重新编译它。
您可能还想试试 App::MoarVM::Debug。 (我没有。)
使用这些方法,您将能够绝对精确地跟踪编译器对您输入的任何代码执行的操作。我建议你这样做,即使我没有这样做。也许你能找出我哪里出错了。
在下文中,我通过直接探索 Rakudo 编译器的源代码来跟踪这个问题。
一个search for "method tail" in the Rakudo sources yielded 4 matches. For my golf the matching method is a match in core/AnyIterableMethods.pm6
.
tail
参数 $n
显然不是 Callable
所以继续我们的探索的相关行是 Rakudo::Iterator.LastNValues(self.iterator,$n,'tail')
.
对此进行搜索会在 core/Iterator.pm6
中找到 this method。
这又调用了this .new
routine。
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
的else分支。它以 nqp::create(self)!SET-SELF(iterator,n,f)
.
这又会调用 !SET-SELF
例程,其中包含以下行:
($!lastn := nqp::setelems(nqp::list, $!size = size)),
尝试将 size
(在我们的 BOOM 案例中是 '1'
)分配给 $!size
。但是 $!size
is declared as:
has int $!size;
宾果。
或者是吗?我不知道我是否真的 正确地找到了问题所在。我只是在探索 github 存储库中的代码,实际上并没有 运行 编译器的检测版本并跟踪其执行,正如在试图找出问题的明智步骤 #3 中所讨论的那样你遇到过。
更糟糕的是,当我运行编译器时,它是一个旧编译器,而我正在探索的代码是 master
...
为什么这样做?
(*,*).tail('1') # OK
此代码路径大概是 this method。参数 $n
不是 Callable
,因此代码路径将 运行 通过在以下行中使用 $n
的路径:
nqp::unless(
nqp::istype($n,Whatever) || $n == Inf,
$iterator.skip-at-least(nqp::elems($!reified) - $n.Int)
$n == Inf
应该不是问题。 ==
会将其操作数强制转换为数字,并且应该注意 $n
为 '1'
.
nqp::elems($!reified) - $n.Int
应该也不是问题。
nqp ops 文档显示 nqp::elems
always returns an int
。所以这归结为一个应该工作的int - Int
。
嗯。
A blame of these lines shows that the .Int
in the last line was only added 3 months ago.
所以,抓住救命稻草,如果尝试会发生什么:
(my int $foo = 1) - '1' # OK
不,这不是问题。
这条路似乎变冷了,或者我已经偏离了实际的执行路径。
我会发布我得到的东西。也许其他人可以从这里拿起它,或者我会在一三天内再去一次...