Utilice Haskell como módulos Prelude en un módulo en raku

11

Estoy escribiendo un paquete de dibujo con algunas partes, y tengo operadores y tipos de datos dispersos en todo. Sin embargo, no quiero que los usuarios agreguen los módulos correspondientes cada vez, ya que sería bastante complicado, por ejemplo, tendría una Pointclase, un Monoidrol y una Styleclase en diferentes rutas como esta

unit module Package::Data::Monoid;
# $?FILE = lib/Package/Data/Monoid.pm6

role Monoid {...}
unit module Package::Data::Point;
# $?FILE = lib/Package/Data/Point.pm6

class Point {...}
unit module Package::Data::Style;
# $?FILE = lib/Package/Data/Style.pm6

class Style {...}

Me gustaría tener un haskellpreludio similar lib/Package/Prelude.pm6 con el efecto de que puedo escribir tales guiones

use Package::Prelude;

# I can use Point right away, Style etc...

en lugar de hacer

use Package::Data::Style;
use Package::Data::Point;
use Package::Data::Monoid;

# I can too use point right away, but for users not knowing the
# inner workings it's too overwhelming

He intentado muchas cosas:

  • Esta versión no me da el efecto correcto, tengo que escribir toda la ruta al punto, es decir, Package::Data::Point...
unit module Package::Prelude;
# $?FILE = lib/Package/Prelude.pm6
use Package::Data::Style;
use Package::Data::Point;
use Package::Data::Monoid;
  • Esta versión me da el Pointderecho de inmediato, pero tengo problemas con los operadores y demás, también me gustaría agregar automáticamente todo, desde las rutinas exportadas en los paquetes de ejemplo mencionados.
# $?FILE = lib/Package/Prelude.pm6
use Package::Data::Style;
use Package::Data::Point;
use Package::Data::Monoid;

sub EXPORT {
  hash <Point> => Point
     , <Style> => Style
     , <mappend> => &mappend
     ...
}

¿Conocen ustedes una forma mejor y más rápida de obtener un archivo similar a un preludio?

margolari
fuente
Puedes usar unit class Package::Data::Point. No tienes que usar module.
Brad Gilbert

Respuestas:

12

El uso EXPORTestá en la dirección correcta. Las cosas clave a saber son:

  • Las importaciones son léxicas
  • Podemos usar la introspección para obtener y acceder a los símbolos en el ámbito léxico actual

Entonces la receta es:

  • use todos los módulos dentro de EXPORT
  • Luego extraiga todos los símbolos importados y devuélvalos como resultado de EXPORT

Como ejemplo, creo un módulo Foo::Point, que incluye un operador y una clase:

unit module Foo::Point;

class Point is export {
    has ($.x, $.y);
}

multi infix:<+>(Point $a, Point $b) is export {
    Point.new(x => $a.x + $b.x, y => $a.y + $b.y)
}

Y, solo para demostrar que puede funcionar con múltiples módulos, también un Foo::Monad:

unit module Foo::Monad;

class Monad is export {
    method explain() { say "Just think of a burrito..." }
}

El objetivo es hacer que esto funcione:

use Foo::Prelude;
say Point.new(x => 2, y => 4) + Point.new(x => 3, y => 5);
Monad.explain;

Lo cual se puede lograr escribiendo un Foo::Preludeque contenga:

sub EXPORT() {
    {
        use Foo::Point;
        use Foo::Monad;
        return ::.pairs.grep(*.key ne '$_').Map;
    }
}

Hay algunas rarezas aquí para explicar:

  1. Una subcuenta de las declaraciones implícitas $_, $/y $!. Exportarlos daría lugar a un error de choque de símbolo en tiempo de compilación cuando el módulo es use'd. Un bloque solo tiene un implícito $_. Por lo tanto, hacemos nuestra vida más fácil con un bloque desnudo anidado.
  2. El grepobjetivo es asegurarnos de que no exportamos nuestro $_símbolo declarado implícitamente (gracias al bloque anidado, es el único que nos debe preocupar).
  3. ::es una forma de hacer referencia al alcance actual (etimología: ::es el separador de paquetes). ::.pairsasí obtiene Pairobjetos para cada símbolo en el alcance actual.

Hay un mecanismo de reexportación especulado que puede aparecer en una futura versión del lenguaje Raku que eliminaría la necesidad de este poco de repetitivo.

Jonathan Worthington
fuente
Finalmente, este es exactamente el comportamiento que estaba buscando, ¡muchas gracias!
margolari