Raku 对 infix(Hyper: Dan::Series, Int) 的模糊调用

Raku Ambiguous call to infix(Hyper: Dan::Series, Int)

我正在写一个模型系列 class(有点像 pandas 中的那个)- 它应该是位置和关联的。

class Series does Positional does Iterable does Associative {
    has Array $.data is required;
    has Array $.index;

    ### Construction ###

    method TWEAK {
        # sort out data-index dependencies
        $!index = gather {
            my $i = 0;
            for |$!data -> $d {
                take ( $!index[$i++] => $d )
            }
        }.Array
    }

    ### Output ### 

    method Str {
        $!index
    }   

    ### Role Support ### 

    # Positional role support
    # viz. https://docs.raku.org/type/Positional

    method of {
        Mu  
    }   
    method elems {
        $!data.elems
    }   
    method AT-POS( $p ) { 
        $!data[$p]
    }   
    method EXISTS-POS( $p ) { 
        0 <= $p < $!data.elems ?? True !! False
    }   

    # Iterable role support
    # viz. https://docs.raku.org/type/Iterable

    method iterator {
        $!data.iterator
    }   
    method flat {
        $!data.flat
    }   
    method lazy {
        $!data.lazy
    }   
    method hyper {
        $!data.hyper
    }   

    # Associative role support
    # viz. https://docs.raku.org/type/Associative

    method keyof {
        Str(Any)
    }   
    method AT-KEY( $k ) { 
        for |$!index -> $p {
            return $p.value if $p.key ~~ $k
        }   
    }   
    method EXISTS-KEY( $k ) { 
        for |$!index -> $p {
            return True if $p.key ~~ $k
        }   
    }   

    #`[ solution attempt #1 does NOT get called
    multi method infix(Hyper: Series, Int) is default {
        die "I was called"
    }
    #]
}

my $s = Series.new(data => [rand xx 5], index => [<a b c d e>]);

say ~$s;
say $s[2];
say $s<b>;

到目前为止非常酷。

我可以去 dd $s.hyper 拿这个

HyperSeq.new(configuration => HyperConfiguration.new(batch => 64, degree => 1))

但是(必须有一个但即将到来),我希望能够对我的系列元素进行超数学运算,例如:

say $s >>+>> 2;

但这会产生:

Ambiguous call to 'infix(Hyper: Dan::Series, Int)'; these signatures all match:
  (Hyper: Associative:D \left, \right, *%_)
  (Hyper: Positional:D \left, \right, *%_)
  in block <unit> at ./synopsis-dan.raku line 63

如何告诉我的 class 系列不提供 Associative hyper 候选...?


注意:根据@raiph 的评论将示例编辑为可运行的 MRE ... 因此,我根据 docs.raku.org

保留了 3 个角色的最低要求

取 ​​#1

首先,MRE 强调 M1:

class foo does Positional does Associative { method of {} }
sub infix:<baz> (\l,\r) { say 'baz' }
foo.new >>baz>> 42;

产量:

Ambiguous call to 'infix(Hyper: foo, Int)'; these signatures all match:
  (Hyper: Associative:D \left, \right, *%_)
  (Hyper: Positional:D \left, \right, *%_)
  in block <unit> at ./synopsis-dan.raku line 63

错误消息显示它是 A) 对名为 infix 的方法的调用,调用者匹配 Hyper,以及 B) 有两种方法可能与该调用匹配。

鉴于您的 MRE 中没有 class Hyper,这些方法和 Hyper class 必须是内置的或泄露的内部细节.

文档搜索没有发现这样的 class。所以 Hyper 是未记录的鉴于该文档最近的覆盖范围相当广泛,这表明 Hyper 是一个内部细节。但无论如何,使用 official/documented 功能似乎无法解决您的问题。

希望这个坏消息还是比none好。2

取 ​​#2

让“非官方功能”等小细节阻止我们做我们想做的事情有什么乐趣?

a core.c module named Hyper.pm6 in the Rakudo source repo.

浏览几秒钟,然后点击它的“历史”和“责备”,我可以立即看到我真的是时候总结这个 SO 答案了,并为你的下一步行动提出建议。

也就是说,我建议你开始 另一个 SO,使用这个答案作为它的核心(但颠倒我的演示顺序,即 starting通过提及 Hyper,并且它不是文档),并检查 Liz 的名称(根据 Hyper 的 History/Blame),将 link 返回到您的 Q 作为其背景。我很确定 会给你一个好的答案,或者至少是一个权威的答案。

脚注

1 我也试过这个:

class foo does Positional does Associative { method of {} }
sub postfix:<bar>(\arg) { say 'bar' }
foo.new>>bar;

但这奏效了(显示 bar)。

2 如果您自己没有得到我的 Take #1 结论,也许那是因为您的 MRE 不是很 M?如果您确实 到达了同一点(参见您的 MRE 中的“解决方案尝试 #1 未被调用”),那么请阅读并在未来的 SO 中牢记智慧"Explain ... any difficulties that have prevented you from solving it yourself".

经过一些实验(以及从对这个 SO 的非常有用的评论中考虑的新方向),我想我已经找到了解决方案:

  1. 从 class 声明中删除 does Associative 角色,如下所示:
class Series does Positional does Iterable {...}

但是

  1. 在 class:
  2. 的正文中保留关联角色支持方法
    # Associative role support
    # viz. https://docs.raku.org/type/Associative

    method keyof {
        Str(Any)
    }   
    method AT-KEY( $k ) { 
        for |$!index -> $p {
            return $p.value if $p.key ~~ $k
        }   
    }   
    method EXISTS-KEY( $k ) { 
        for |$!index -> $p {
            return True if $p.key ~~ $k
        }   
    }   

这给了我位置访问器和关联访问器,以及函数式超数学运算符:

my $s = Series.new(data => [rand xx 5], index => [<a b c d e>]);

say ~$s;        #([a => 0.6137271559776396 b => 0.7942959887386045 c => 0.5768018697817604 d => 0.8964323560788711 e => 0.025740150933493577] , dtype: Num)

say $s[2];      #0.7942959887386045
say $s<b>;      #0.5768018697817604
say $s >>+>> 2; #(2.6137271559776396 2.7942959887386047 2.5768018697817605 2.896432356078871 2.0257401509334936)

虽然这感觉有点单薄(并且可能缺少全套关联函数),但我相当有信心基本方法会让我精简访问,就像来自密钥的散列 我寻求的能力。它不再创建模棱两可的调用。

这个解决方案可能有点作弊,因为我知道我会接受的妥协程度;-)。