Використовуйте Haskell як модулі Prelude в модулі в raku


11

Я пишу пакет креслень з деякими частинами, і у мене є оператори та типи даних, що розкидані через групу. Однак я не хочу, щоб користувачі щоразу додавали відповідні модулі, оскільки це було б дуже безладно, наприклад, я мав би Pointклас, Monoidроль та Styleклас у різних шляхах, як це

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

Мені хотілося б зробити haskellподібну прелюдію lib/Package/Prelude.pm6 з тим, що я можу писати такі сценарії

use Package::Prelude;

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

а не робити

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

Я спробував багато речей:

  • Ця версія не дає мені належного ефекту, я повинен набрати весь шлях до точки, тобто 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відразу, але у мене виникають проблеми з операторами і так далі, також я просто хотів би автоматично додати все з експортованих процедур у згадані приклади пакетів.
# $?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
     ...
}

Чи знаєте ви, хто краще і швидше може отримати такий файл, що нагадує прелюдію?


Можна використовувати unit class Package::Data::Point. Не потрібно користуватися module.
Бред Гілберт

Відповіді:


12

Використання EXPORTв правильному напрямку. Ключові речі, які слід знати:

  • Імпорт лексичний
  • Ми можемо використовувати самоаналіз для отримання та доступу до символів у поточній лексичній області

Тож рецепт такий:

  • use всі модулі всередині EXPORT
  • Потім витягнути всі імпортовані символи та повернути їх як результат EXPORT

Як приклад, я створюю модуль Foo::Point, що включає оператор і клас:

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

І, лише щоб продемонструвати це, можна працювати з декількома модулями, також Foo::Monad:

unit module Foo::Monad;

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

Мета полягає в тому, щоб зробити цю роботу:

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

Чого можна досягти, написавши а, Foo::Preludeщо містить:

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

Тут є декілька дивацтв, щоб пояснити:

  1. subМає неявні декларації $_, $/і $!. Експорт цих даних призведе до помилки зіткнення символу часу компіляції, коли модуль use'd. Блок має лише неявне $_. Таким чином, ми полегшуємо своє життя за допомогою вкладеного голого блоку.
  2. Потрібно grepпереконатися, що ми не експортуємо наш неявно оголошений $_символ (завдяки вкладеному блоку - це єдиний, про який нам потрібно піклуватися).
  3. ::є способом посилання на поточну область застосування (етимологія: ::це роздільник пакетів). ::.pairsТаким чином, отримуються Pairоб'єкти для кожного символу в поточному масштабі.

Існує розроблений спекульований механізм реекспорту, який може з’явитися у майбутньому випуску мови Raku, який би усунув необхідність у цьому бітній котлі.


Нарешті, саме така поведінка, яку я шукав, дуже дякую!
margolari
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.