如何创建和导出动态运算符

how to create and export dynamic operators

我有一些 类(并且还需要更多)看起来像这样:

use Unit;

class Unit::Units::Ampere is Unit
{
  method TWEAK { with self {
    .si            = True;
                   #     m·  kg·   s·   A   ·K· mol·  cd
    .si-signature  = [   0,   0,   0,   1,   0,   0,   0 ];
    .singular-name = "ampere";
    .plural-name   = "ampere";
    .symbol        = "A";
  }}

  sub postfix:<A> ($value) returns Unit::Units::Ampere is looser(&prefix:<->) is export(:short) {
    return Unit::Units::Ampere.new( :$value );
  };

  sub postfix:<ampere> ($value) returns Unit::Units::Ampere is looser(&prefix:<->) is export(:long) {
    $value\A;
  };
}

我希望能够在运行时动态构建和导出自定义运算符。我知道如何使用 EXPORT,但如何即时创建后缀运算符?

对于第一个问题,您可以通过从另一个返回子来创建动态子。要仅接受 Ampere 参数(其中以编程方式选择 "Ampere"),请在函数签名中使用 type capture

sub make-combiner(Any:U ::Type $, &combine-logic) {
    return sub (Type $a, Type $b) {
        return combine-logic($a, $b);
    }
}

my &int-adder = make-combiner Int, {$^a + $^b};
say int-adder(1, 2);
my &list-adder = make-combiner List, {(|$^a, |$^b)};
say list-adder(<a b>, <c d>);
say list-adder(1, <c d>); # Constraint type check fails

请注意,当我定义内部 sub 时,我必须在 sub 关键字之后放置一个 space,以免编译器认为我正在调用一个名为 "sub"。 (请参阅我的答案末尾了解另一种方法。)

现在,进入困难的部分:如何导出其中一个生成的函数? is export 真正作用的文档在这里:https://docs.perl6.org/language/modules.html#is_export

在页面的一半位置,他们有一个向符号 table 添加函数的示例,而无法在编译时编写 is export 。为了使上述工作正常,它需要在一个单独的文件中。要查看以编程方式确定的名称和以编程方式确定的逻辑的示例,请创建以下 MyModule.pm6:

unit module MyModule;

sub make-combiner(Any:U ::Type $, &combine-logic) {
    anon sub combiner(Type $a, Type $b) {
        return combine-logic($a, $b);
    }
}

my Str $name = 'int';
my $type = Int;
my package EXPORT::DEFAULT {
    OUR::{"&{$name}-eater"} := make-combiner $type, {$^a + $^b};
}

调用 Perl 6:

perl6 -I. -MMyModule -e "say int-eater(4, 3);"

正如所希望的那样,输出是 7。请注意,在这个版本中,我使用了 anon sub,它允许您命名生成的函数 "anonymous"。我知道这主要用于生成更好的堆栈跟踪。

综上所述,我在动态设置后缀运算符的优先级时遇到了问题。我觉得你需要修改operator的Precedence角色,或者自己创建,而不是让编译器帮你创建。这没有记录。

我基本上做了 this:

sub EXPORT
{
    return %(
        "postfix:<A>" => sub is looser(&prefix:<->) {
            #do something
          }
    );
}

简单得令人不安。