Tipos parametrizados en Raku, cómo usar valores de tiempo de ejecución como parámetros

Nov 28 2020

Me gustaría crear algunos tipos parametrizados para Raku; básicamente, me gustaría crear algunas clases diferentes cuya principal diferencia sería el rango de valores de uno de sus atributos; por ejemplo, las clases representan tipos de edificios, me gustaría tener diferentes clases para edificios con 3 o cualquier otro número de pisos. Así que esto es lo mejor que pude pensar:

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;

Esto es claramente poco práctico en cuanto necesitas cuidar muchos números diferentes de pisos (no aquí en Granada, donde tienen como máximo 10, creo, pero bueno ...). El problema aquí es básicamente que necesita tener la información de los subconjuntos en el momento de la compilación, por lo que a menos que use macros (aún experimentales), no hay forma de que pueda usar ningún tipo de variable. Entonces, ¿puede pensar en una forma práctica de definir este tipo de roles curry para cualquier valor del parámetro?

Respuestas

8 user0721090601 Nov 28 2020 at 15:51

En realidad, a diferencia de lo que dije en mi anterior, puedes usar condiciones en cláusulas where sin problema, solo necesitas encerrarlas entre llaves:

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

Eso debería cubrir todos los tipos de asignaciones

5 raiph Nov 28 2020 at 04:15

Tengo chuletas de fregado muy limitadas, y lo siguiente parece feo, pero funciona y podría ser un paso en la dirección correcta.

Qué he hecho:

  • Construyó dinámicamente una matriz de 10,000 subsetsa través del MOP.

  • El tiempo cambió su construcción para compilar el tiempo a través de BEGIN.

  • Usó un elemento apropiado de la matriz para parametrizar el rol.

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

Intenté usar wherecláusulas anónimas , pero de manera similar fue en vano, pero rastreé el problema: whereel BUILDmétodo aparentemente ignora la cláusula . No estoy seguro de si es porque tiene acceso directo (vía $!floor) que omite la wherecláusula, o si está sucediendo algo más extraño (probablemente lo último, lo obtuve en general Nilsi intenté usar el valor paramaterizado en una wherecláusula).

No obstante, esto debería funcionar bien, incluido un mensaje de error útil:

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

Puede ver lo fácil que sería modificar si asumiera que los pisos siempre lo están 0 .. x, o x .. ypodría proporcionar un mensaje de error aún más útil.

1 raiph Nov 29 2020 at 21:38

Una respuesta que cubre el caso de que un lector conoce Java pero no Raku.

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

tipos parametrizados para Raku

El ejemplo de Java vinculado es:

La instanciación de un tipo genérico con argumentos de tipo reales se denomina tipo parametrizado. Ejemplo (de un tipo parametrizado):

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

Un análogo razonable de Raku es:

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

El Positionaltipo es un rol parametrizable . Un rol especifica una interfaz y / o implementación parcial de un tipo. Creo que el de Raku Positionales suficientemente análogo al de Java Collectionque sirve para los propósitos de esta respuesta.

El Arraytipo es una clase parametrizable . Especifica una estructura de datos que se adhiere al Positionalrol. No es una lista vinculada, pero será suficiente para los propósitos de esta respuesta.