Parametrisierte Typen in Raku, wie Laufzeitwerte als Parameter verwendet werden

Nov 28 2020

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

8 user0721090601 Nov 28 2020 at 15:51

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

5 raiph Nov 28 2020 at 04:15

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 subsets ü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 
3 user0721090601 Nov 28 2020 at 01:40

Ich habe versucht, anonyme whereKlauseln zu verwenden, aber ähnlich ohne Erfolg, aber ich habe das Problem aufgespürt: Die whereKlausel wird anscheinend von der BUILDMethode ignoriert . Ich bin mir nicht sicher, ob es daran liegt, dass es direkten Zugriff (via $!floor) hat, der die whereKlausel umgeht , oder ob etwas anderes Seltsames vor sich geht (wahrscheinlich letzteres, das ich im Allgemeinen erhalten habe, Nilwenn ich versucht habe, den parametrisierten Wert in einer whereKlausel 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 .. yund eine noch hilfreichere Fehlermeldung anzeigen.

1 raiph Nov 29 2020 at 21:38

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 Positionalist so analog zu Java, Collectiondass es für die Zwecke dieser Antwort dient.

Der ArrayTyp ist eine parametrierbare Klasse . Es gibt eine Datenstruktur an, die der PositionalRolle entspricht. Es ist keine verknüpfte Liste, aber es wird für die Zwecke dieser Antwort ausreichen.