Parametrisierte Typen in Raku, wie Laufzeitwerte als Parameter verwendet werden
Ich möchte einige parametrisierte Typen für Raku erstellen . Grundsätzlich möchte ich einige verschiedene Klassen erstellen, deren Hauptunterschied der Wertebereich eines seiner Attribute ist. Zum Beispiel stellen Klassen Gebäudetypen dar. Ich hätte gerne verschiedene Klassen für Gebäude mit 3 oder einer anderen Anzahl von Stockwerken. Das ist also das Beste, was ich mir vorstellen kann:
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;
Dies ist eindeutig unpraktisch, sobald Sie sich um viele verschiedene Stockwerke kümmern müssen (nicht hier in Granada, wo sie höchstens 10 haben, denke ich, aber gut ...). Das Problem hierbei ist, dass Sie zum Zeitpunkt der Kompilierung über die Informationen für Teilmengen verfügen müssen. Wenn Sie also keine Makros verwenden (noch experimentell), können Sie keine Variablen verwenden. Können Sie sich also eine praktische Möglichkeit vorstellen, diese Art von Curry-Rollen für einen beliebigen Wert des Parameters zu definieren?
Antworten
Anders als ich in meinem vorherigen gesagt habe, können Sie Bedingungen verwenden, in denen Klauseln ohne Probleme nur in geschweifte Klammern gesetzt werden müssen:
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
Das sollte alle Zuordnungstypen abdecken
Ich habe nur sehr begrenzte MOP-Chops, und das Folgende scheint hässlich, aber es funktioniert und könnte ein Schritt in die richtige Richtung sein.
Was ich getan habe:
Dynamisches Erstellen eines Arrays von 10.000
subset
s über die MOP.Die Zeit verschob ihre Konstruktion, um die Zeit über zu kompilieren
BEGIN
.Verwendete ein geeignetes Element aus dem Array, um die Rolle zu parametrisieren.
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
Ich habe versucht, anonyme where
Klauseln zu verwenden, aber ähnlich ohne Erfolg, aber ich habe das Problem aufgespürt: Die where
Klausel wird anscheinend von der BUILD
Methode ignoriert . Ich bin mir nicht sicher, ob es daran liegt, dass es direkten Zugriff (via $!floor
) hat, der die where
Klausel umgeht , oder ob etwas anderes Seltsames vor sich geht (wahrscheinlich letzteres, das ich im Allgemeinen erhalten habe, Nil
wenn ich versucht habe, den parametrisierten Wert in einer where
Klausel zu verwenden).
Dies sollte jedoch gut funktionieren, einschließlich einer hilfreichen Fehlermeldung:
role Zipi[$condition] {
has $.floor; submethod BUILD(:$floor, |c) {
die "Invalid floor number."
unless $floor ~~ $condition;
$!floor = $floor;
}
}
Sie können sehen, wie einfach es ist, Änderungen vorzunehmen, wenn Sie davon ausgehen können, dass Fußböden immer vorhanden sind 0 .. x
, x .. y
und eine noch hilfreichere Fehlermeldung anzeigen.
Eine Antwort auf den Fall, dass ein Leser Java kennt, aber nicht Raku.
Collection<String> coll = new LinkedList<String>();
parametrisierte Typen für Raku
Das verknüpfte Java-Beispiel lautet:
Die Instanziierung eines generischen Typs mit tatsächlichen Typargumenten wird als parametrisierter Typ bezeichnet. Beispiel (eines parametrisierten Typs):
Collection<String> coll = new LinkedList<String>();
Ein vernünftiges Raku-Analogon ist:
my Positional[Str] \coll = Array[Str].new;
Der PositionalTyp ist eine parametrierbare Rolle . Eine Rolle gibt eine Schnittstelle und / oder eine teilweise Implementierung eines Typs an. Ich glaube, Rakus Positional
ist so analog zu Java, Collection
dass es für die Zwecke dieser Antwort dient.
Der ArrayTyp ist eine parametrierbare Klasse . Es gibt eine Datenstruktur an, die der Positional
Rolle entspricht. Es ist keine verknüpfte Liste, aber es wird für die Zwecke dieser Antwort ausreichen.