Int(酷)强制的重点是什么?

mus*_*iKk 11 perl6 raku

关于功能的Perl 6网站说

强制类型可以帮助您在例程中使用特定类型,但接受更广泛的输入.调用例程时,参数会自动转换为较窄的类型.

sub double(Int(Cool) $x) {
    2 * $x
}

say double '21';    # 42
say double Any;     # Type check failed in binding $x; expected 'Cool' but got 'Any'
Run Code Online (Sandbox Code Playgroud)

这里Int是强制参数的目标类型,而Cool是例程接受作为输入的类型.

但这个潜艇有什么意义呢?是不是$x只是一个Int?为什么要限制调用者Cool为参数实现?

我通过加倍的例子困惑,因为Int已经is Cool.所以我做了一个示例,其中类型不共享层次结构:

class Foo { method foomethod { say 'foomethod' } }
class Bar {}

class Quux is Foo {
# class Quux { # compile error
  method Bar { Bar.new }
}

sub foo(Bar(Foo) $c) {
  say $c.WHAT;    # (Bar)
  # $c.foomethod  # fails if uncommented: Method 'foomethod' not found for invocant of class 'Bar'
}

foo(Quux.new)
Run Code Online (Sandbox Code Playgroud)

这里的invocant foo被限制为提供一个Foo可以转换为a Barfoo甚至不能调用Fooon 的方法,$c因为它的类型 Bar.那么为什么要foo关心那个被强制的类型Foo呢?

有人可以对此有所了解吗?还要感谢指向相应文档和规范部分的链接.我找不到任何有用的东西.

Bra*_*ert 5

这样做是接受一个Cool的子类型的值,并尝试将其转换为Int.在这一点上它一种诠释,不管它是什么了.

所以

sub double ( Int(Cool) $n ) { $n * 2 }
Run Code Online (Sandbox Code Playgroud)

真的可以被认为是(我认为这是它在Rakudo实际实现的方式)

# Int is a subtype of Cool otherwise it would be Any or Mu
proto sub double ( Cool $n ) {*}

# this has the interior parts that you write
multi sub double (  Int $n ) { $n * 2 }

# this is what the compiler writes for you
multi sub double ( Cool $n ) {
    # calls the other multi since it is now an Int
    samewith Int($n);
}
Run Code Online (Sandbox Code Playgroud)

因此,它接受Int,Str,Rat,FatRat,Num,Array,Hash等中的任何一个,并尝试在使用它之前将其转换为Int&infix:<*>,并且2.

say double '  5  '; # 25
say double 2.5;     # 4
say double [0,0,0]; # 6
say double { a => 0, b => 0 }; # 4
Run Code Online (Sandbox Code Playgroud)

您可以将其限制为Cool而不是Any,因为所有Cool值基本上都需要为Int提供强制.

(:( Int(Any) $ )可缩短为:( Int() $ ))


你可能会这样做的原因是你需要它Int在sub中,因为你正在调用其他代码来执行不同类型的不同操作.

sub example ( Int(Cool) $n ) returns Int {
    other-multi( $n ) * $n;
}

multi sub other-multi ( Int $ ) { 10 }
multi sub other-multi ( Any $ ) {  1 }

say example 5;   # 50
say example 4.5; # 40
Run Code Online (Sandbox Code Playgroud)

在这种特殊情况下,您可以将其写为其中之一

sub example ( Cool $n ) returns Int {
    other-multi( Int($n) ) * Int($n);
}

sub example ( Cool $n ) returns Int {
    my $temp = Int($n);
    other-multi( $temp ) * $temp;
}

sub example ( Cool $n is copy ) returns Int {
    $n = Int($n);
    other-multi( $n ) * $n;
}
Run Code Online (Sandbox Code Playgroud)

它们都不像使用签名来强制它的那个一样清晰.


通常对于这样一个简单的功能,你可以使用其中一个,它可能会做你想要的.

my &double = * * 2; # WhateverCode
my &double = * × 2; # ditto

my &double = { $_ * 2 };       # bare block
my &double = { $^n * 2 };      # block with positional placeholder
my &double = -> $n { $n * 2 }; # pointy block

my &double = sub ( $n ) { $n * 2 } # anon sub
my &double = anon sub double ( $n ) { $n * 2 } # anon sub with name

my &double = &infix:<*>.assuming(*,2); # curried
my &double = &infix:<*>.assuming(2);

sub double ( $n ) { $n * 2 } # same as :( Any $n )
Run Code Online (Sandbox Code Playgroud)


rai*_*iph 5

更新今天回答了这个答案我得出结论我完全误解了@musiKk的所作所为.在@ darch的问题和@ musiKk的回答中最清楚地揭示了这一点:

@darch:或者你的问题是为什么人们可能更喜欢Int(酷)而不是Int(Any)?如果是这样的话,那就是要问的问题.

@musiKk:这正是我的问题.:)

回顾其他许多答案,我认为没有人按我现在认为的方式解决这个问题.

我当然可能是错的,所以我决定做的就是保留原来的问题,特别是保留标题,并保留原来的答案,而是写一个新的答案来解决@darch的重新制定问题.

指定参数类型,没有强制: Int $x

我们可以声明:

sub double (Int $x) { ... } # Accept only Int. (No coercion.)
Run Code Online (Sandbox Code Playgroud)

然后这将工作:

double(42);
Run Code Online (Sandbox Code Playgroud)

但不幸的是打字42响应这个:

double(prompt('')); # `prompt` returns the string the user types
Run Code Online (Sandbox Code Playgroud)

导致double调用失败,Type check failed in binding $x; expected Int but got Str ("42")因为42虽然看起来像一个数字,但在技术上是一个类型的字符串Str,我们没有要求强制.

使用全面强制指定参数类型: Int() $x

我们可以在sub的签名中引入任意值的毯式强制:

sub double (Int(Any) $x) { ... } # Take Any value. Coerce to an Int.
Run Code Online (Sandbox Code Playgroud)

要么:

sub double (Int() $x)    { ... } # Same -- `Int()` coerces from Any.
Run Code Online (Sandbox Code Playgroud)

现在,如果42double(prompt(''));语句提示时键入,则运行时类型检查失败不再适用,而是运行时尝试将字符串强制转换为Int.如果用户键入格式正确的数字,则代码才有效.如果他们输入123abc强制,将在运行时失败,并显示一条错误消息:

Cannot convert string to number: trailing characters after number in '123?abc'
Run Code Online (Sandbox Code Playgroud)

任何值的毯式强制的一个问题是这样的代码:

class City { ... } # City has no Int coercion
my City $city;
double($city);
Run Code Online (Sandbox Code Playgroud)

在运行时失败并显示以下消息:"找不到'City'类调用的方法'Int'".

使用Cool值强制指定参数类型: Int(Cool) $x

我们可以选择任何价值的强制和全面强制之间的平衡点.

强制来自的最佳类通常是Cool类,因为保证Cool值可以很好地强制转换为其他基本类型或生成一个很好的错误消息:

# Accept argument of type Cool or a subclass and coerce to Int:
sub double (Int(Cool) $x) { ... }
Run Code Online (Sandbox Code Playgroud)

有了这个定义,以下内容:

double(42);
double(prompt(''));
Run Code Online (Sandbox Code Playgroud)

尽可能地工作,并且:

double($city);
Run Code Online (Sandbox Code Playgroud)

失败了"类型检查失败绑定$ x;预期酷但得到城市(城市)"这对于程序员而言可以说比"方法'Int'没有找到类'城市'的调用"更好一些.


为什么foo会首先关注那个被胁迫的类型是Foo?

希望现在显而易见的是,值得限制强制类型的唯一原因Foo是因为这是一种预期成功强制转换为Bar价值的类型(或者,也许是通过友好消息失败).

有人可以对此有所了解吗?还要感谢指向相应文档和规范部分的链接.我找不到任何有用的东西.

您最初引用的文档几乎都是针对最终用户文档的.希望它现在有意义,你已经准备好了.如果没有请评论,我们将从那里开始.