Reputation: 671
I'm writing a drawing package with some parts, and I have operators and data types scattered througout. However I don't want the users to add the corresponding modules every time, since it would be quite messy, for instance I'd have a Point
class, a Monoid
role and a Style
class
in different paths like this
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 {...}
I would like to have a haskell
like prelude in lib/Package/Prelude.pm6
with the effect that I can write such scripts
use Package::Prelude;
# I can use Point right away, Style etc...
instead of doing
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
I've tried many things:
Package::Data::Point
...unit module Package::Prelude;
# $?FILE = lib/Package/Prelude.pm6
use Package::Data::Style;
use Package::Data::Point;
use Package::Data::Monoid;
Point
right away, but I get
problems with the operators and so on, also I would just like to
add automatically everything from the exported routines in the mentioned
example packages.# $?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
...
}
Do you people know a better and quick way of getting such a prelude-like file?
Upvotes: 10
Views: 209
Reputation: 29454
Using EXPORT
is in the right direction. The key things to know are:
So the recipe is:
use
all the modules inside of EXPORT
EXPORT
As an example, I create a module Foo::Point
, including an operator and a class:
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)
}
And, just to demonstrate it can work with multiple modules, also a Foo::Monad
:
unit module Foo::Monad;
class Monad is export {
method explain() { say "Just think of a burrito..." }
}
The goal is to make this work:
use Foo::Prelude;
say Point.new(x => 2, y => 4) + Point.new(x => 3, y => 5);
Monad.explain;
Which can be achieved by writing a Foo::Prelude
that contains:
sub EXPORT() {
{
use Foo::Point;
use Foo::Monad;
return ::.pairs.grep(*.key ne '$_').Map;
}
}
There's a few oddities in here to explain:
sub
has implicit declarations of $_
, $/
, and $!
. Exporting these would result in a compile-time symbol clash error when the module is use
'd. A block only has an implicit $_
. Thus we make our life easier with a nested bare block.grep
is to make sure we don't export our implicitly declared $_
symbol (thanks to the nested block, it's the only one we have to care about).::
is a way to reference the current scope (etymology: ::
is the package separator). ::.pairs
thus obtains Pair
objects for each symbol in the current scope.There's a speculated re-export mechanism that may appear in a future Raku language release that would eliminate the need for this bit of boilerplate.
Upvotes: 12