Perl6:如何从Int派生自己的区分类型?

chi*_*chi 5 types static-typing user-defined-types perl6

我想在Perl 6中定义两种数据类型,这些数据类型源自Int但不同时Int或彼此不兼容.

例如:

  • Distance派生自Int0到32000的范围,和
  • Offset派生自Int-32000到32000的范围

现在我想要这些类型Distance,Offset并且Int默认情况下可以区分并且彼此不兼容.

所以(伪Perl 6):

  my Distance $d = Distance(12);  // ok
  my Offset $o = Offset(-1);      // ok
  my Distance $d2 = $o;           // BUMMER!

  sub myprint(Int $i) { say $i }

  say $d + $o;                    // BUMMER!
  myprint $d;                     // BUMMER!
  myprint Int($d);                // ok
Run Code Online (Sandbox Code Playgroud)

等等!如果我试图隐含地混合Distances和Offsets,我希望Perl 6编译器抱怨.

在我迄今读过的书中,没有提示如何实现这一点.问谷歌几天也没有给我任何答案是否可能,如果是,如何?

我发现subset但是这只对一个类型设置了一些限制,但是没有使它与原始类型不兼容.此外,如果在原始类型及其子集中都满足其限制,则它与原始类型无法区分.

所以我想在这里询问是否有人知道Perl 6中是否可以这样做?如果是的话,我该怎么办呢?

Cur*_*mes 5

好吧,如果你真的希望它们在默认情况下是可区分的和不兼容的,只需将它们设置为完全独立的类即可。您可以定义您想要的任何能力。如果您使用与整数的“has a”关系(而不是“is a”关系),则可以很容易地将功能委托给该值(在本示例中,我进行了委托,.Int因此您的示例将起作用):

class Distance
{
    has Int $!value handles<Int>;

    method new($value where 0 <= * <= 32000) { self.bless(:$value) }

    submethod BUILD(:$!value) {}
}

class Offset
{
    has Int $!value handles<Int>;

    method new($value where -32000 <= * <= 32000) { self.bless(:$value) }

    submethod BUILD(:$!value) {}
}

my Distance $d = Distance.new(12); # ok
my Offset $o = Offset.new(-1);     # ok
my Distance $d2 = $o;              # Bummer! Type check fail

sub myprint(Int $i) { say $i }

say $d + $o;                       # Bummer!, can't add those objects 
myprint $d;                        # Bummer!, $d isn't an Int, can't print
myprint Int($d);                   # ok, prints 12, converting with Int
Run Code Online (Sandbox Code Playgroud)

无论您想要什么功能Distance,都Offset必须构建到这些类中,可能会委托给 来$!value使其变得容易。

编辑:如果您确实想要所需的语法,my Distance $d = Distance(12);您可以向Int类添加一个方法来调用构造函数:

Int.^add_method('Distance', method () { Distance.new(self) });
Int.^compose;
Run Code Online (Sandbox Code Playgroud)

我实际上不会建议这样做——可能更令人困惑而不是有帮助。更好地鼓励标准构造函数的使用。@raiph 还指出了惯用的 Perl:

my Distance $d .= new(12);
Run Code Online (Sandbox Code Playgroud)