2016-08-18 26 views
8

Podejrzewam, że to może być błąd w Rakudo, ale zacząłem grać dzisiaj z Perlem 6, więc jest duża szansa, że ​​popełniam błąd. W tym prostym programie deklarowanie tablicy pisanej wewnątrz suba powoduje, że kompilator Perla 6 jest zły. Usunięcie adnotacji typu w tablicy powoduje usunięcie błędu kompilatora.Perl 6 zgłasza "Nie można rozpakować obiektu typu" podczas pisania tablicy

Oto prosty liczba pierwsza znalezieniu programu:

#!/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); 

Na Rakudo Gwiazdy 2016.07.1 (od Fedora 24 repo), program ten daje następujący błąd:

[[email protected] 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 

Jeśli usunąć adnotacja typu w tablicy vals, program działa poprawnie:

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

Czy popełniam błąd w moim korzystaniu z Perla 6, czy jest to błąd w Rakudo?

Odpowiedz

12

Istnieje potencjalny błąd w kodzie, który złapany przez typ sprawdzania

komunikat o błędzie masz zwraca uwagę na linię 8:

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

Linia ta wyznacza listę wartości po prawej stronie = do listy elementów po lewej stronie.

Pierwszy element na liście po lewej stronie, @vals[2*$i], otrzymuje zero.

Nie zdefiniowałeś więcej wartości po prawej, więc reszta elementów po lewej stronie ma przypisany Mu. Mu s ładnie działają jako elementy zastępcze dla elementów, które nie mają określonego typu i nie mają określonej wartości. Pomyśl o wartości Mu, która jest, między innymi, typu Null, z wyjątkiem tego, że jest bezpieczna.

uzyskać ten sam scenariusz z tego golfed wersję:

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

Jak widać, wszystko działa dobrze, gdy robisz nie określić wyraźne ograniczenie typu dla pierwiastków z @vals szyk.

Jest tak, ponieważ domyślnym ograniczeniem typu dla elementów tablicy jest Mu. Przypisanie elementu Mu jest więc w porządku.


Jeśli uważało, że zaostrzone kodu można jednoznacznie przypisać zer:

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

To generuje (lazy) nieskończoną listę zer na RHS tak że zerowy jest przypisany do każdego z lista elementów na LHS.

Po tej zmianie Twój kod zadziała nawet po określeniu ograniczenia typu dla @vals.


Jeżeli nie robisz wprowadzić xx Inf ale zrobić określić ograniczenie typu element @vals że nie jest Mu, następnie Twój kod nie powiedzie się test typu, jeśli spróbujesz przypisać do Mu element @vals.

Błąd sprawdzania typu pojawi się w jednym z dwóch smaków w zależności od tego, czy używasz typów obiektów, czy typów natywnych.

Jeśli określisz ograniczenie typu obiektu (np Int):

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

wtedy masz coś błędu takiego:

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

Jeśli określisz natywnego typu ograniczenia (np int raczej niż Int):

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

t Kiedy kompilator próbuje najpierw uzyskać odpowiednią wartość natywną od wartości obiektu (to się nazywa "unboxing") przed próbą sprawdzenia typu. Ale nie ma odpowiedniej natywnej wartości odpowiadającej wartości obiektu (Mu). Tak więc kompilator skarży się, że nie może nawet rozpakować wartości. Wreszcie, jak wskazano na początku, podczas gdy Mu działa świetnie jako bezpieczny typ Null, to tylko jeden aspekt Mu. Innym jest to, że jest to "type object". Tak więc komunikat o błędzie jest Cannot unbox a type object.

+1

Dzięki za jasne wyjaśnienie. Początkowo miałem nadzieję, że będzie się zachowywał jak numpy lub matlab (które niejawnie rozszerzają listę), ale twoja sugestia robi to, co chcę wyraźnie, co może być lepsze (leniwe nieskończone listy są świetne). – Sultan