Usa Haskell come i moduli Prelude in un modulo in raku


11

Sto scrivendo un pacchetto di disegno con alcune parti e ho operatori e tipi di dati sparsi in tutto. Tuttavia, non voglio che gli utenti aggiungano i moduli corrispondenti ogni volta, poiché sarebbe piuttosto disordinato, ad esempio avrei una Pointclasse, un Monoidruolo e una Styleclasse in percorsi diversi come questo

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 {...}

Mi piacerebbe avere un haskellpreludio simile lib/Package/Prelude.pm6 con l'effetto di poter scrivere tali script

use Package::Prelude;

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

invece di fare

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

Ho provato molte cose:

  • Questa versione non mi dà l'effetto giusto, devo digitare l'intero percorso da puntare, cioè Package::Data::Point...
unit module Package::Prelude;
# $?FILE = lib/Package/Prelude.pm6
use Package::Data::Style;
use Package::Data::Point;
use Package::Data::Monoid;
  • Questa versione mi dà Pointsubito, ma ho problemi con gli operatori e così via, inoltre vorrei solo aggiungere automaticamente tutto dalle routine esportate nei pacchetti di esempio citati.
# $?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
     ...
}

Conoscete la gente un modo migliore e veloce per ottenere un file simile a un preludio?


È possibile utilizzare unit class Package::Data::Point. Non è necessario usare module.
Brad Gilbert,

Risposte:


12

L'uso EXPORTè nella giusta direzione. Le cose chiave da sapere sono:

  • Le importazioni sono lessicali
  • Possiamo usare l'introspezione per ottenere e accedere ai simboli nell'attuale ambito lessicale

Quindi la ricetta è:

  • use tutti i moduli all'interno di EXPORT
  • Quindi estrarre tutti i simboli importati e restituirli come risultato da EXPORT

Ad esempio, creo un modulo Foo::Point, incluso un operatore e una classe:

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)
}

E, solo per dimostrare che può funzionare con più moduli, anche un Foo::Monad:

unit module Foo::Monad;

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

L'obiettivo è far funzionare questo:

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

Che può essere raggiunto scrivendo un Foo::Preludeche contiene:

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

Ci sono alcune stranezze qui per spiegare:

  1. Una subha dichiarazioni implicite di $_, $/e $!. L'esportazione di questi comporterebbe un errore di scontro di simboli in fase di compilazione quando il modulo è use'd. Un blocco ha solo un implicito $_. Così rendiamo la nostra vita più facile con un blocco nudo nidificato.
  2. Lo scopo grepè assicurarci di non esportare il nostro $_simbolo implicitamente dichiarato (grazie al blocco nidificato, è l'unico di cui dobbiamo preoccuparci).
  3. ::è un modo per fare riferimento all'ambito attuale (etimologia: ::è il separatore di pacchetti). ::.pairsottiene quindi Pairoggetti per ciascun simbolo nell'ambito corrente.

C'è un meccanismo di riesportazione speculato che potrebbe apparire in una futura versione in lingua Raku che eliminerebbe la necessità di questo pezzo di boilerplate.


Infine, questo è esattamente il comportamento che stavo cercando, grazie mille!
margolari
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.