Perl6:.sort()不使用覆盖的cmp

时间:2018-12-13 11:37:15

标签: perl6

根据the documentationsort使用infix:<cmp>进行比较。

但是:

class Point
{
    has Int $.x;
    has Int $.y;
    method Str { "($!x,$!y)" }
    method gist { self.Str }
}
multi sub infix:<cmp>(Point $a, Point $b) { $a.y cmp $b.y || $a.x cmp $b.x }

my @p = Point.new(:3x, :2y), Point.new(:2x, :4y), Point.new(:1x, :1y);
say @p.sort;

给出输出:

((1,1) (2,4) (3,2))

当我使用时:

say @p.sort(&infix:<cmp>);

确实给出正确的输出:

((1,1) (3,2) (2,4))

这是文档中的错误,功能还是缺陷? 有没有一种方法可以使.sort()列表上的Point使用自定义排序顺序,而无需指定例程?

2 个答案:

答案 0 :(得分:5)

我认为这是“ Broken By Design”案例。请考虑以下代码段:

my $a = Point.new(:3x, :2y);
my $b = Point.new(:2x, :4y);

say &infix:<cmp>.WHICH;
say $a cmp $b;

{
    multi sub infix:<cmp>(Point $a, Point $b) { $a.y cmp $b.y || $a.x cmp $b.x }
    say &infix:<cmp>.WHICH;
    say $a cmp $b;
}

say &infix:<cmp>.WHICH;
say $a cmp $b;

新的多重候选的定义将生成一个仅在词法上可见的新原型子。由于sort方法是在设置中定义的(概念上是一个封闭的作用域),因此不会看到新的多重候选。

也许可以使sort动态&infix:<cmp>而不是按词法查找,尽管我怀疑这样的更改将不得不等待6.e,即使我们认为这是我们想要做的事情,这不是给定的。

作为解决方法,您可以执行类似的操作

constant CMP = &infix:<cmp>;
multi sub infix:<cmp>(Point $a, Point $b) { ... }
BEGIN CMP.wrap(&infix:<cmp>);

目前,尽管我不一定会推荐它(与被认为有害的全球性国家以及所有爵士乐打交道)...

答案 1 :(得分:3)

正在使用的cmpsort中词法范围内的cmp,而不是您定义的cmp。如果将几行更改为:

multi sub infix:<cmp>(Point $a, Point $b) { 
  say "Hey $a $b";
  $a.y cmp $b.y || $a.x cmp $b.x 
}
my @p = Point.new(:3x, :2y), Point.new(:2x, :4y), Point.new(:1x, :1y);
say @p.sort( { $^b cmp $^a } );

由于使用的cmp属于实际词法范围,因此可以正确调用它:

Hey (2,4) (3,2) Hey (1,1) (2,4) Hey (1,1) (3,2) ((2,4) (3,2) (1,1))

按要求。