Sparametryzowane typy w Raku, jak używać wartości czasu wykonywania jako parametrów
Chciałbym stworzyć sparametryzowane typy dla Raku; w zasadzie chciałbym stworzyć kilka różnych klas, których główną różnicą byłby zakres wartości jednego z jego atrybutów; na przykład klasy reprezentują typy budynków, chciałbym mieć różne klasy dla budynków z 3 lub dowolną inną liczbą pięter. Więc to najlepsze, o czym mogłem pomyśleć:
subset Two-Tops of UInt where * <=2;
subset Three-Tops of UInt where * <=3;
role Zipi[ ::Capper ] {
has Capper $.floor; } class Capped-at-three does Zipi[Three-Tops] {} my $capped = Capped-at-three.new( floor => 2 );
say $capped.raku;
Jest to oczywiście niepraktyczne, gdy trzeba zadbać o wiele różnych ilości pięter (nie tutaj, w Granadzie, gdzie mają co najwyżej 10, jak sądzę, ale cóż ...). Problem polega na tym, że po prostu musisz mieć informacje o podzbiorach w czasie kompilacji, więc jeśli nie używasz makr (nadal eksperymentalnych), nie ma możliwości użycia jakiejkolwiek zmiennej. Czy możesz więc pomyśleć o praktycznym sposobie zdefiniowania tego rodzaju curried ról dla dowolnej wartości parametru?
Odpowiedzi
Właściwie, w przeciwieństwie do tego, co powiedziałem w moim poprzednim, możesz używać warunków, w których klauzule bez problemu, wystarczy je zamknąć w nawiasach:
role Zipi[$condition] { has $.floor is rw where {$_ ~~ $condition}
method foo($x) { $!floor = $x } } class A does Zipi[2 < * < 5] { method bar($x) { $.floor = $x }
}
#my $a = A.new( floor => 10); # error my $a = A.new( floor => 4); # OK
#$a.foo(10); # error $a.foo(3); # OK
#$a.bar(0); # error $a.bar(4); # OK
#$a.floor = 9; # error $a.floor = 3; # OK
Powinno to obejmować wszystkie typy przydziałów
Mam bardzo ograniczone kotlety MOP, a poniższe wydaje się brzydkie, ale działa i może być krokiem we właściwym kierunku.
Co ja zrobiłem:
Dynamicznie skonstruowano tablicę 10 000
subset
sekund za pomocą MOP.Czas przesunął ich konstrukcję do czasu kompilacji za pośrednictwem
BEGIN
.Użyto odpowiedniego elementu z tablicy do sparametryzowania roli.
my @max-floors-checkers;
BEGIN {
@max-floors-checkers = do for ^10_000 -> \floors {
Metamodel::SubsetHOW.new_type:
refinee => UInt,
refinement => { $^floors <= floors } } } role BuildingCategory[ ::MaxFloorsCheck ] { has MaxFloorsCheck $.floors }
class Capped-at-three does BuildingCategory[ @max-floors-checkers[3] ] {}
my $capped3 = Capped-at-three.new( floors => 2 ); say $capped3.raku; # Capped-at-three.new(floors => 2
my $capped4 = Capped-at-three.new( floors => 4 ); # Type check failed
Próbowałem użyć anonimowych where
klauzul, ale podobnie bezskutecznie, ale wyśledziłem problem: where
klauzula jest najwyraźniej ignorowana przez BUILD
metodę. Nie jestem pewien, czy to dlatego, że ma bezpośredni dostęp (przez $!floor
), który omija where
klauzulę, czy też dzieje się coś innego dziwnego (prawdopodobnie to drugie, generalnie otrzymałem, Nil
gdy próbowałem użyć wartości sparametryzowanej w where
klauzuli).
Niemniej powinno to działać dobrze, w tym podając pomocny komunikat o błędzie:
role Zipi[$condition] {
has $.floor; submethod BUILD(:$floor, |c) {
die "Invalid floor number."
unless $floor ~~ $condition;
$!floor = $floor;
}
}
Możesz zobaczyć, jak łatwo byłoby to zmodyfikować, jeśli możesz założyć, że podłogi są zawsze 0 .. x
, lub możesz x .. y
podać jeszcze bardziej pomocny komunikat o błędzie.
Odpowiedź dotycząca sprawy: czytelnik zna Javę, ale nie zna Raku.
Collection<String> coll = new LinkedList<String>();
sparametryzowane typy dla Raku
Powiązany przykład Java to:
Wystąpienie typu ogólnego z rzeczywistymi argumentami typu jest nazywane typem sparametryzowanym. Przykład (typu sparametryzowanego):
Collection<String> coll = new LinkedList<String>();
Rozsądnym analogiem Raku jest:
my Positional[Str] \coll = Array[Str].new;
PositionalTyp to parametryzowalny rola . Rola określa interfejs i / lub częściową implementację typu. Uważam, że Raku Positional
jest wystarczająco analogiczny do Java, Collection
że służy do celów tej odpowiedzi.
ArrayTyp to parametryzowalny klasa . Określa strukturę danych, która jest zgodna z Positional
rolą. To nie jest lista z linkami, ale wystarczy do tego, by odpowiedzieć na nie.