Types paramétrés dans Raku, comment utiliser les valeurs d'exécution comme paramètres

Nov 28 2020

J'aimerais créer des types paramétrés pour Raku; en gros, j'aimerais créer des classes différentes dont la principale différence serait la plage de valeurs de l'un de ses attributs; par exemple, les classes représentent des types de bâtiments, j'aimerais avoir des classes différentes pour les bâtiments à 3 ou tout autre nombre d'étages. C'est donc le meilleur auquel je puisse penser:

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;

Ce n'est clairement pas pratique dès lors qu'il faut s'occuper de nombreux nombres d'étages différents (pas ici à Grenade, où ils en ont au plus 10, je pense, mais bon ...). Le problème ici est fondamentalement que vous devez avoir les informations pour les sous-ensembles au moment de la compilation, donc à moins que vous n'utilisiez des macros (encore expérimentales), il n'y a aucun moyen d'utiliser n'importe quel type de variable. Pouvez-vous donc penser à un moyen pratique de définir ce type de rôles curry pour n'importe quelle valeur du paramètre?

Réponses

8 user0721090601 Nov 28 2020 at 15:51

En fait, contrairement à ce que j'ai dit dans mon précédent, vous pouvez utiliser des conditions dans les clauses where sans problème, il vous suffit de les mettre entre accolades:

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

Cela devrait couvrir tous les types d'affectation

5 raiph Nov 28 2020 at 04:15

J'ai des côtelettes MOP très limitées, et ce qui suit semble moche, mais cela fonctionne et pourrait être un pas dans la bonne direction.

Ce que j'ai fait:

  • Construit dynamiquement un tableau de 10 000 subsets via le MOP.

  • Le temps a décalé leur construction pour compiler le temps via BEGIN.

  • Utilisé un élément approprié du tableau pour paramétrer le rôle.

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

J'ai essayé d'utiliser des whereclauses anonymes , mais de la même manière en vain, mais j'ai retrouvé le problème: la whereclause est apparemment ignorée par la BUILDméthode. Je ne sais pas si c'est parce qu'il a un accès direct (via $!floor) qui contourne la whereclause, ou si quelque chose d'autre bizarre se passe (probablement ce dernier, j'ai généralement obtenu Nilsi j'essayais d'utiliser la valeur paramétrée dans une whereclause).

Néanmoins, cela devrait fonctionner correctement, y compris en donnant un message d'erreur utile:

role Zipi[$condition] {
    has $.floor; submethod BUILD(:$floor, |c) {
        die "Invalid floor number."
            unless $floor ~~ $condition;
        $!floor = $floor;
    }
}

Vous pouvez voir comment il serait facile de modifier si vous pouvez supposer que les étages sont toujours 0 .. x, ou x .. yet pourraient fournir un message d'erreur encore plus utile.

1 raiph Nov 29 2020 at 21:38

Une réponse couvrant le cas où un lecteur connaît Java mais pas Raku.

Collection<String> coll = new LinkedList<String>();

types paramétrés pour Raku

L'exemple Java lié est:

L'instanciation d'un type générique avec des arguments de type réels est appelée un type paramétré. Exemple (de type paramétré):

Collection<String> coll = new LinkedList<String>();

Un analogue Raku raisonnable est:

my Positional[Str] \coll = Array[Str].new;

Le Positionaltype est un rôle paramétrable . Un rôle spécifie une interface et / ou une implémentation partielle d'un type. Je crois que celui de Raku Positionalest suffisamment analogue à celui de Java pour Collectionqu'il serve aux fins de cette réponse.

Le Arraytype est une classe paramétrable . Il spécifie une structure de données qui adhère au Positionalrôle. Ce n'est pas une liste chaînée mais elle suffira pour les besoins de cette réponse.