2016-11-21 23 views
7

W Perl 6, można iteracyjne dosłownego sekwencji:Jak mogę przekazać sekwencję jako parametr w Perlu 6?

.say for 0 ... 3; 

można wiązać się skalarną i powtórzyć, że:

my $s := 0 ... 3; 
.say for $s; 

ale nie mogą wiązać się ze skalarnym, przechodzą jako argument, a następnie iteracyjne że:

my $t := 0 ... 3; 
show($t); 

sub show ($seq) { .say for $seq } 

podprogram pobiera pojedynczy element typu Seq, ale nie iteracyjne go.

0 
1 
2 
3 
0 
1 
2 
3 
(0 1 2 3) 

Czy coś w trakcie przygotowywania parametru przechodzi już przez wszystko?

Odpowiedz

10

Wartość przechowywane w Scalar pojemnika jest nie automatycznie powtórzyć

Choć obie $s i $seqscalars (aka „zmienne”) $s jest związana bezpośrednio do wartości Seq natomiast swojej $seq jest związany z pośrednik Scalar (pamiętaj, wielkie litery S) "kontener", który z kolei zawiera Seq. Wartość przechowywana w kontenerze Scalar to , a nie automatycznie iterowana, gdy jest używana z funkcjami takimi jak for.


Bardziej szczegółowo:

my $s := 0 ... 3; 
.say for $s; 

Ponieważ zmienna zgłoszenie my wykorzystuje napęd bezpośredni wiązania := inicjalizacji, $s jest bezpośrednio związana z jedną wartością 0 ... 3 Sekw.

Oznacza to, że instrukcja for widzi pojedynczą wartość Seq, określa, że ​​spełnia rolę Iterable, i spłaszcza (iteruje).

Teraz pomyśl o tym:

my $s := 0 ... 3; 
my $container = $s; 
.say for $container; 

Ponieważ druga deklaracja my wykorzystuje operator przypisania = inicjalizacji, nowa zmienna $container najpierw związany z nowym Scalar pojemniku, który następnie „zawiera” cokolwiek zostanie przydzielony.

Zgodnie z językiem szeroko Slurpy Conventions (w szczególności: „An iterowalny wewnątrz skalarnym pojemniku nie liczy”), A for oświadczenie nie iteracji wartość posiadanych w skalarnym pojemnika, więc linia .say for $container robi tylko jeden say .

Podobna sytuacja dotyczy oryginalnej procedury show, ponieważ deklaracje parametrów zmiennych są domyślnie kontenerami (semantycznymi).

Jedną z opcji jest zamiast dodać is raw cechę do parametru $seq:

sub show ($seq is raw) { .say for $seq } 

Zapobiega to zwykle automatyczne wiązanie $seq do skalara pojemnika (które z kolei zawierają wartość SEQ) w ramach połączenie z show.

Innym rozwiązaniem jest umożliwienie $seq być zobowiązany do skalara pojemnika, lecz wyraźnie spłaszczyć (iteracji) zmienną $seq w ciele rutyny show użyciu prefiksu |:

sub show ($seq) { .say for |$seq } 
6

Zamiast cecha is raw parametr sugerowane przez raiph, można również użyć zmiennej Sigil mniej jako parametr, który nie wprowadza Scalar pojemnika:

sub show (\seq) { .say for seq } 

(Można również użyć tego formularza do normalnych zmiennych, jak w my \a = 5; say a;, ale należy pamiętać, że są one tylko jednego przydziału.)

Odmiana ta jest formą +, który przechodzi na surowcu argumentu, jeśli jest to Iterable (jak List lub Seq), ale gdy nie iterable argumentem jest przekazywana promuje go do List jednego elementu, tak że ciało funkcji może polegać na zawsze otrzymuję Iterable:

sub show (+seq) { .say for seq } 

(To jest większość wbudowanych procedur przetwarzania list, takich jak grep i zip use)

Oczywiście jeśli wolisz używać parametru $ która wprowadza Scalar pojemnik, można po prostu „decontainerize” ponownie przed iteracji nad nim, poprzez wywołanie metody .list na nim.

sub show ($seq) { .say for $seq.list } # explicit 

sub show ($seq) { .say for @$seq }  # short-hand syntax 

(Aktualizacja: Eh, .list w rzeczywistości zamienia Seq w List, tj. Nie będzie pamięci wydajne w przypadku dużych Seq. Korzystanie z |$seq, tak jak już odkryłeś we własnej odpowiedzi, nie ma tego problemu.)

+0

Dzięki! Ale tak, myślę o nieskończonych, leniwych sekwencjach. :) –