在子模块中重用父符号

发布于 2025-01-11 17:12:27 字数 1460 浏览 0 评论 0原文

我正在寻求在子模块中重复使用与其父模块中相同的角色/类名称。你知道,就像一个专业。

目的是通过简单地将顶部的 use Dan 更改为 use Dan::Pandas ,能够为父系列和子系列变体重复使用相同的脚本代码。

我试图坚持角色而不是类组成,以便可以将行为应用于其他对象,例如。 class GasBill does Series;

这是 MRE:

me@ubuntu:~/spike# tree
.
├── lib
│   ├── Dan
│   │   └── Pandas.rakumod
│   └── Dan.rakumod
└── spike.raku

Dan.rakumod:

  1 unit module Dan;
  2 
  3 role Series is export {
  4     method no { "no" }
  5 }

Pandas.rakumod:

  1 unit module Dan::Pandas;
  2 
  3 use Dan;
  4 
  5 role Series does Dan::Series is export {
  6     method yo { "yo" }
  7 }

spike.raku:

  1 use lib './lib';
  2 use Dan::Pandas;
  3 
  4 my $s = Series.new;                  #version 1                      
  5 #my $s = Dan::Pandas::Series.new;    #version 2 "fqm"
  6 
  7 say $s.no, $s.yo, $s.^name;

我的版本 1 说:

No appropriate parametric role variant available for 'Dan::Series':
    Ambiguous call to '(Dan::Series)'; these signatures all match:
      (::$?CLASS ::::?CLASS Mu $)
      (::$?CLASS ::::?CLASS Mu $)
  in block <unit> at spike.raku line 4

我的版本 2 说:

Could not find symbol '&Series' in 'Dan::Pandas'
  in block <unit> at spike.raku line 5

我相信 raku 确实有办法做这个,但是该死的,如果我能解决的话!

I am seeking to re-use the same role/class names in a child module as in its parent. You know, like a specialization.

The aim is to be able to re-use the same script code for both the parent and child Series variants by simply changing use Dan to use Dan::Pandas at the top.

I am trying to stick to role rather than class compostion where I can so that the behaviours can be applied to other objects with eg. class GasBill does Series;

Here is the MRE:

me@ubuntu:~/spike# tree
.
├── lib
│   ├── Dan
│   │   └── Pandas.rakumod
│   └── Dan.rakumod
└── spike.raku

Dan.rakumod:

  1 unit module Dan;
  2 
  3 role Series is export {
  4     method no { "no" }
  5 }

Pandas.rakumod:

  1 unit module Dan::Pandas;
  2 
  3 use Dan;
  4 
  5 role Series does Dan::Series is export {
  6     method yo { "yo" }
  7 }

spike.raku:

  1 use lib './lib';
  2 use Dan::Pandas;
  3 
  4 my $s = Series.new;                  #version 1                      
  5 #my $s = Dan::Pandas::Series.new;    #version 2 "fqm"
  6 
  7 say $s.no, $s.yo, $s.^name;

My version 1 says:

No appropriate parametric role variant available for 'Dan::Series':
    Ambiguous call to '(Dan::Series)'; these signatures all match:
      (::$?CLASS ::::?CLASS Mu $)
      (::$?CLASS ::::?CLASS Mu $)
  in block <unit> at spike.raku line 4

My version 2 says:

Could not find symbol '&Series' in 'Dan::Pandas'
  in block <unit> at spike.raku line 5

I am trusting that raku does have a way to do this, but darned if I can work it out!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

撑一把青伞 2025-01-18 17:12:27

TL;DR 您需要一个解决方案来避免两个角色具有相同的全名。

高尔夫

role R {}
role R {}
R.new

显示:(

No appropriate parametric role variant available for 'R':
    Ambiguous call to '(R)'; these signatures all match:
      (::$?CLASS ::::?CLASS Mu $)
      (::$?CLASS ::::?CLASS Mu $)

请参阅编写存根角色时的直觉引用警告对错误消息进行更多讨论。)

解决方案

  1. Just Dan

    • Dan.rakumod

      单元模块丹;
      
      角色系列是 export { method no { "no" } }
      
    • spike.raku

      使用 lib '.';
      
      使用丹;
      
      我的 $s = Series.new;
      
      .say for $s.?no, $s.?yo, $s.^name;
      
    • 运行spike显示:

      <前><代码>否

      丹::系列

  2. Introduce Dan::Pandas

    • 更改 Dan,以便变体模块可以使用而无需它们导入 Dan< /code> 的非限定 Series 符号进入其词法范围。

      (因为否则 Dan 的未限定 Series 符号最终会位于其词法范围以及自己的中em> 不合格的 Series 符号,并且您会收到“不明确的调用”错误。)

    • 单元模块丹;
      
      角色系列是 export { method no { "no" } }
      
      类 Dan::Variant-Export-Dummy-Type 是 export(:Variant-Exports) {}
      

      更改是最后一行,一个带有新导出标记的虚拟声明。 (以更简洁的方式介绍新标签,留给读者作为练习。)

    • 丹::熊猫:

      单元模块 Dan::Pandas;
      
      使用 Dan :Variant-Exports;
      
      角色 Series 的作用 Dan::Series 是导出 { method yo { "yo" } }
      

      更改是使用新的 :Variant-Exports 标记和 use Dan ... 语句。这会阻止 DanSeries 角色以该非限定名称导入 Dan::Pandas


  3. 用户程序现在将按预期/想要的方式工作。

    • 只需更改 spike.raku 中的 use 语句即可:

      使用 lib '.';
      
      使用 Dan::Pandas;
      
      我的 $s = Series.new;
      
      .say for $s.?no, $s.?yo, $s.^name;
      
    • 仅对用户程序进行此更改即可运行:

      <前><代码>否

      丹::熊猫::系列

    • 请注意,使用这些模块的程序无需了解 :Variant-Exports 标记。这只是 Dan 模块和 Dan::Pandas 等模块的内部细节,可以让它们避免本答案开头所示的意外角色变体重复问题。< /p>

TL;DR You need a solution that avoids having two roles with the same full name.

Golf

role R {}
role R {}
R.new

displays:

No appropriate parametric role variant available for 'R':
    Ambiguous call to '(R)'; these signatures all match:
      (::$?CLASS ::::?CLASS Mu $)
      (::$?CLASS ::::?CLASS Mu $)

(See Gut-referencing warning when composing stubbed role for a bit more discussion of the error message.)

A solution

  1. Just Dan.

    • Dan.rakumod:

      unit module Dan;
      
      role Series is export { method no { "no" } }
      
    • spike.raku:

      use lib '.';
      
      use Dan;
      
      my $s = Series.new;
      
      .say for $s.?no, $s.?yo, $s.^name;
      
    • Running spike displays:

      no
      Nil
      Dan::Series
      
  2. Introduce Dan::Pandas.

    • Alter Dan so variant modules can use it without them importing Dan's unqualified Series symbol into their lexical scopes.

      (Because otherwise Dan's unqualified Series symbol ends up being in their lexical scopes as well as their own unqualified Series symbol, and you get the "Ambiguous call" error.)

    • Dan:

      unit module Dan;
      
      role Series is export { method no { "no" } }
      
      class Dan::Variant-Export-Dummy-Type is export(:Variant-Exports) {}
      

      The change is the last line, a dummy declaration with a new export tag. (Introducing the new tag some cleaner way is left as an exercise for readers.)

    • Dan::Pandas:

      unit module Dan::Pandas;
      
      use Dan :Variant-Exports;
      
      role Series does Dan::Series is export { method yo { "yo" } }
      

      The change is using the new :Variant-Exports tag with the use Dan ... statement. This stops Dan's Series role being imported under that unqualified name into Dan::Pandas.

  3. User programs will now work as expected/wanted.

    • Just change the use statement in spike.raku:

      use lib '.';
      
      use Dan::Pandas;
      
      my $s = Series.new;
      
      .say for $s.?no, $s.?yo, $s.^name;
      
    • Running with just this change for user programs:

      no
      yo
      Dan::Pandas::Series
      
    • Note how there's no need for programs using using these modules to know about the :Variant-Exports tag. That's just an internal detail of the Dan module and the Dan::Pandas etc modules that lets them avoid the unintended role variant duplication problem shown at the start of this answer.

迷爱 2025-01-18 17:12:27

如果我理解正确,您不需要/不想在最终模块中使用非专业角色(也就是说,您没有使用 Dan.xml 中定义的 Series )。 spike.raku 中的 rakumod – 您仅使用 Pandas.rakumod 中定义的专用 Series)。这是正确的吗?

如果是这样,解决方案很简单:只需不要从 Dan.rakumod导出 Series – 它仍然是我们的 范围(角色的默认值),因此您仍然可以按照当前的方式在 Pandas.rakumod 中使用它 (Dan::Series)。但是,由于它未导出,因此不会与无前缀的 Series 产生名称冲突。

If I'm understanding correctly, you don't need/want to use the non-specialized role in the final module (that is, you aren't using the Series defined in Dan.rakumod in spike.raku – you're only using the specialized Series defined in Pandas.rakumod). Is that correct?

If so, the solution is simple: just don't export the Series from Dan.rakumod – it's still our scoped (the default for roles) so you can still use it in Pandas.rakumod exactly the way you currently do (Dan::Series). But, since it's not exported, you it won't create a name clash with the non-prefixed Series.

平定天下 2025-01-18 17:12:27

我的解决方案

采纳 @codesections [FQM 可以在没有 is export 的情况下使用] 和 @raiph [您可以使用例如 is export(:ALL) 限定导出的建议],然后 - 是的 - 有一个巧妙的方法可以做到这一点。

即。 https://docs.raku.org/language/modules#Exporting_and_selective_importing

事实证明这是低接触(只需更改两行),并且正如我最初希望的那样,raku 设计师已经预料到了这一点。

这是我的OP调整后的代码...

Dan.rakumod:

  1 unit module Dan;
  2 
  3 role Series is export(:ALL) {    #<== added the selective export
  4     method no { "no" }
  5 }  

Pandas.rakumod(无变化):

  1 unit module Dan::Pandas;
  2 
  3 use Dan;
  4 
  5 role Series does Dan::Series is export {
  6     method yo { "yo" }
  7 }  

spike.raku:

  1 use lib './lib';
  2 #use Dan::Pandas;     #\ either of these work
  3 use Dan :ALL;         #/ <== use :ALL to get 'Series'
  4 
  5 my $s = Series.new;
  6 
  7 say $s.no, $s.yo, $s.^name;  #No such method 'yo' if Pandas not used

My Solution

Taking the advice of @codesections [that FQMs can be used without is export] and @raiph [that you can qualify the export with e.g. is export(:ALL)], then - yes - there is a neat way to do this.

viz. https://docs.raku.org/language/modules#Exporting_and_selective_importing

Turns out that this is low touch (just change two lines) and, as I originally hoped, something that raku designers have anticipated.

Here is the code from my OP adjusted...

Dan.rakumod:

  1 unit module Dan;
  2 
  3 role Series is export(:ALL) {    #<== added the selective export
  4     method no { "no" }
  5 }  

Pandas.rakumod (no change):

  1 unit module Dan::Pandas;
  2 
  3 use Dan;
  4 
  5 role Series does Dan::Series is export {
  6     method yo { "yo" }
  7 }  

spike.raku:

  1 use lib './lib';
  2 #use Dan::Pandas;     #\ either of these work
  3 use Dan :ALL;         #/ <== use :ALL to get 'Series'
  4 
  5 my $s = Series.new;
  6 
  7 say $s.no, $s.yo, $s.^name;  #No such method 'yo' if Pandas not used
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文