ใช้ Haskell เหมือนโมดูลโหมโรงในโมดูลใน 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คุณไม่จำเป็นต้องใช้
Brad Gilbert

คำตอบ:


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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.