【问题标题】:how to create and export dynamic operators如何创建和导出动态运算符
【发布时间】:2017-11-06 11:36:57
【问题描述】:

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

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,但如何动态创建后缀运算符?

【问题讨论】:

    标签: raku


    【解决方案1】:

    我最终基本上是在做this:

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

    这太简单了。

    【讨论】:

    • 您介意我在 EXPORT 文档中添加一个版本吗?这是一个巧妙的技巧,我知道您所说的“令人不安的简单”是什么意思。
    • 不,我为什么要这样做?
    【解决方案2】:

    对于第一个问题,您可以通过从另一个返回一个子来创建动态子。要仅接受 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 关键字之后放置一个空格,以免编译器认为我在调用一个名为“sub”的函数。 (有关另一种方法,请参阅我的答案的结尾。)

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

    在页面的一半处,他们有一个向符号表添加函数但无法在编译时写入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,它允许您命名“匿名”生成的函数。我知道这主要用于生成更好的堆栈跟踪。

    说了这么多,我在动态设置后缀运算符的优先级时遇到了麻烦。我认为您需要修改操作员的Precedence 角色,或者自己创建它,而不是让编译器为您创建它。这没有记录。

    【讨论】:

    • 您不需要使用&amp; 调用&amp; sigiled 函数。 sub foo ( &amp;bar, $arg ){ say bar $arg }。事实上sub foo ($a){ say $a }my &amp;foo = -&gt; $a { say $a } 基本相同
    • sub make-combiner ( Any:U ::Type $, &amp;combine-logic ){ anon sub combiner ( Type $a, Type $b ) { combine-logic $a, $b }}
    • @BradGilbert 谢谢,我在示例中清理了它。
    • 您需要删除.,因为这确实需要使用&amp;
    • @BradGilbert 感谢所有提示!我已经合并了它们。 ::Type 类型捕获特别爽!
    猜你喜欢
    • 2010-09-11
    • 1970-01-01
    • 2020-01-09
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 1970-01-01
    相关资源
    最近更新 更多