Perl 6报告"无法取消打包类型对象"键入数组时

时间:2016-08-18 20:58:13

标签: perl6 rakudo

我怀疑这可能是Rakudo的一个错误,但我今天刚开始玩Perl 6,所以我很有可能只是犯了一个错误。在这个简单的程序中,在sub中声明一个类型化数组似乎会使Perl 6编译器生气。删除数组上的类型注释可以消除编译器错误。

这是一个简单的素数查找程序:

#!/usr/bin/env perl6
use v6;

sub primes(int $max) {
    my int @vals = ^$max; # forcing a type on vals causes compiler error (bug?)
    for 2..floor(sqrt($max)) -> $i {
        next if not @vals[$i];
        @vals[2*$i, 3*$i ... $max-1] = 0;
    }
    return ($_ if .Bool for @vals)[1..*];
}

say primes(1000);

在Rakudo Star 2016.07.1(来自Fedora 24 repos)上,该程序出现以下错误:

[sultan@localhost p6test]$ perl6 primes.p6 
Cannot unbox a type object
  in sub primes at primes.p6 line 8
  in block <unit> at primes.p6 line 13

如果我删除了vals数组上的类型注释,程序可以正常工作:

    ...
    my @vals = ^$max; # I removed the int type
    ...

我在使用Perl 6时犯了错误,或者这是Rakudo中的错误?

1 个答案:

答案 0 :(得分:13)

您的代码中存在类型检查所带来的潜在错误

您收到的错误消息引起了对第8行的注意:

@vals[2*$i, 3*$i ... $max-1] = 0;

此行将=右侧的值列表分配给左侧元素列表。

左侧列表中的第一个元素@vals[2*$i]获得零。

您没有在右侧定义更多值,因此左侧的其余元素将分配MuMu可以很好地用作没有特定类型且没有特定值的元素的占位符。将Mu视为除了其他东西之外,就像Null一样,除了它的类型安全。

使用这个高尔夫版本可以获得相同的场景:

my @vals;
@vals[0,1] = 0; # assigns 0 to @vals[0], Mu to @vals[1]

正如您所见,当@vals数组的元素指定显式类型约束时,一切正常。

这是因为数组元素的默认类型约束是Mu。因此,为元素分配Mu很好。

如果您觉得它收紧了代码,您可以明确指定零:

@vals[2*$i, 3*$i ... $max-1] = 0 xx Inf;

这会在RHS上生成一个(懒惰的)无限列表,以便为LHS上的每个元素列表分配零。

即使您为@vals指定了类型约束,只需进行此更改,您的代码也会正常工作。

如果您没有介绍xx Inf执行@vals指定的元素类型约束不是Mu,如果您尝试将Mu分配给@vals元素,则代码将无法通过类型检查。

类型检查失败将以两种风格之一出现,具体取决于您是使用对象类型还是本机类型。

如果指定对象类型约束(例如Int):

my Int @vals;
@vals[0,1] = 0;

然后你会收到类似这样的错误:

Type check failed in assignment to @vals; expected Int but got Mu (Mu)

如果您指定原生类型约束(例如int而不是Int):

my int @vals;
@vals[0,1] = 0;

然后编译器首先尝试从对象值生成合适的本机值(这称为&#34;取消装箱&#34;),然后再尝试进行类型检查。但是没有与对象值(Mu)对应的合适的原生值。所以编译器抱怨它甚至无法取消装箱值。最后,正如开头所暗示的那样,虽然Mu作为一种类型安全的Null很有效,但它只是Mu的一个方面。另一个是它是"type object"。因此错误消息为Cannot unbox a type object