Perl 6类型推断

dha*_*ech 10 type-inference perl6 raku

鉴于:

sub abc(Int $n) { say $n }
Run Code Online (Sandbox Code Playgroud)

如果我们传递一个类型的变量Str,abc我们会得到一个编译时错误:

my Str $s = "123";   abc $s;
Run Code Online (Sandbox Code Playgroud)

如果我们传递一个包含字符串的无类型变量,我们会收到运行时错误:

my $s = "123";   abc $s;
Run Code Online (Sandbox Code Playgroud)

C++支持auto允许类型推断的关键字.

是否可以auto在Perl 6中定义类似于:

auto $s = "123";
Run Code Online (Sandbox Code Playgroud)

会导致$s输入Str

即,我们可以做到以下几点:

auto $s = "123";   abc $s;
Run Code Online (Sandbox Code Playgroud)

并得到一个编译时错误.

rai*_*iph 7

可以auto在Perl 6中定义类似的东西

我认为是这样的.但我将不得不将您的问题翻译成三个不同的问题,以提供更有用的答案.

对于我对下面前两个问题的回答,请参考我写的关于此的reddit评论.我的评论分为四个部分,由横向规则分隔.第一部分和最后部分与您的问题相关.

是否可以修改Perl 6语言?

是.

您可以或多或少地从用户区代码中随意修改Perl 6语言.

从我上面链接的评论的第一部分引用一个要点:

  • 使用语法构建的内部俚语DSL,如外部DSL,但通过俚语机制与标准Perl 6语法混合使用.必须编写这些DSL,以便至少与标准Perl 6语法进行一些基本协调.用这种DSL编写的代码是内联的,与常规代码无法区分.相关幻灯片.

引用我写的最后一部分:

虽然可以实施俚语......但它们并未获得官方支持......并且不像他们需要的那样含糖.

是否可以编写与编译器通信的编译时宏?

是.

遗憾的是,您还无法定义语句宏,这是新类型的变量声明所需要的.引用上面链接的评论中的最后一部分:

"对于你想要一个内部DSL,但它在语法上与标准Perl 6冲突而只是使用用户定义的例程和运算符的情况下的预期设计选项是......写一个is parsed宏[或]写一个俚语.这些中的任何一个都可以,从理论上讲,解析你想要的任何语法.但is parsed宏还没有降落,看起来至少还有一三年的时间 - 它们仍然只是007中讨论的一个设计概念.

是否有可能将新想法融入Perl 6?

是.

只需实施您的想法并游说其中.可能从俚语开始.可能只是直接破解整个编译器.

我对最后一点非常认真.

Rakudo Perl 6编译器当然是开源的.

更重要的是,它主要是用Perl 6编写的.(而且不是Perl 6的大多数是nqp,它基本上是完整Perl 6的一个子集.)

结论

如果你能写一些基本的Perl 6代码; 愿意在freenode IRC频道上提出大量问题#perl6-dev ; 并且耐心; 那么你应该能够在Perl 6中实现任何想法,你的auto想法似乎相对简单.

(假设我已经正确地理解了他们所面临的问题,那么通过"相对"我想象一个知识渊博的核心开发者可以在几个小时内做出概念验证.有一天,当俚语和/或宏可能需要大约一个小时才能更加精致.)


jjm*_*elo 5

您正在寻找的可能就是我们在Perl6中所谓的allomorphs,根据上下文可以表现不同的类型.对于您发布的特定情况,有IntStr allomorph:

sub abc(Int $n) { say $n }
my IntStr $s = <123>;
abc $s; # prints 123
Run Code Online (Sandbox Code Playgroud)

(请注意,它需要引用词<>而不是通常的"").通常,同质异形体是它们可以被类型化的类的子类; IntStr子类IntStr.对于您想要的任何类型auto,只要它们可以相互转换,这通常可以完成.

另一个选择,如果你已经知道你将得到什么以及它将变成什么,就是使用强制:

sub bcd(Int(Str) $n) { say $n }
my $t = "123";
bcd $t; # prints 123
Run Code Online (Sandbox Code Playgroud)

在这种情况下,在子程序体使用之前,字符串将被强制转换IntCapture中的字符串.

最后,只要在有效使用变量时使用,就可以使用数字上下文.

sub efg($n) { say +$n }
my Int $u = 123;
my Str $v = "123";
efg $u;
efg $v;
Run Code Online (Sandbox Code Playgroud)

+将变量放在数字上下文中,自动将其转换为数字.如果要将其限制为Int或Str,您甚至可以将其转换为签名约束

sub xyz($n where $_ ~~ Int | Str ) { say +$n }
xyz $u;
xyz $v;
xyz $t;
xyz $s;
Run Code Online (Sandbox Code Playgroud)

(它使用上面定义的变量)这里无论变量没有分配类型(如$t,或已被定义为IntStr,IntStr),它都将起作用.只要它可以被smartmatched到Int或者Str,它将被送入子本体,并通过语境变成一个数字.

完整的程序在这里,以防万一你想下载并检查它.

  • 问题是你想要约束到字符串的东西不应该有另一种类型的逃逸舱口. (2认同)

dwa*_*ing 5

我只是想提一下Proxies.这些工作在容器级别,仅在运行时.但是要提供一些控制或跟踪变量内容的能力.

sub auto($v?) is rw {
    my $val = $v;
    Proxy.new(
        FETCH => -> $, { $val },
        STORE => -> $, $new-val {
            die "You canna change type from {$val.WHAT.^name} to {$new-val.WHAT.^name}"
                unless $new-val.WHAT ~~ $val.WHAT;
            $val = $new-val;
        }
    )
}

my $i := auto(11);
$i = 69;
say $i;
$i = 'blah'; # Boom
Run Code Online (Sandbox Code Playgroud)

Proxys可用于实现类似的auto类型,但仅限于运行时且仅在容器级别.它们也不是那么防水,因为与变量相关的容器可能会发生变化.例如,使用绑定:=运算符

$i := 'he he'; # changed container
Run Code Online (Sandbox Code Playgroud)