如何对Raku函数的数组参数的条目进行类型约束?

我试图定义一个子程序Raku,其理由是,比方说,一个阵列的诠释S(强加的约束,即拒绝那些参数不是 ArrayS的IntS)。

问题:实现这一目标的“最佳”方式是什么(最惯用的,或最直接的,或者您认为“最佳”在这里应该是什么意思)?

RakuREPL 中运行的示例如下。

我所希望的会奏效

> sub f(Int @a) {1}
&f
> f([1,2,3])
Type check failed in binding to parameter '@a'; expected Positional[Int] but got Array ([1, 2, 3])
  in sub f at <unknown file> line 1
  in block <unit> at <unknown file> line 1

另一个非工作示例

> sub f(@a where *.all ~~ Int) {1}
&f
> f([1,2,3])
Constraint type check failed in binding to parameter '@a'; expected anonymous constraint to be met but got Array ([1, 2, 3])
  in sub f at <unknown file> line 1
  in block <unit> at <unknown file> line 1

虽然

> [1,2,3].all ~~ Int
True

什么工作

两种变体

> sub f(@a where { @a.all ~~ Int }) {1}

> sub f(@a where { $_.all ~~ Int }) {1}

给我我想要的:

> f([5])
1
> f(['x'])
Constraint type check failed in binding to parameter '@a'; expected anonymous constraint to be met but got Array (["x"])
  in sub f at <unknown file> line 1
  in block <unit> at <unknown file> line 1

我过去使用过它,但它让我觉得有点笨拙/冗长..

补充说明

Int @a我最初尝试的语法并不完全是假的,但我不知道什么时候应该通过,什么时候不应该通过。

例如,我可以在课堂上做到这一点:

> class A { has Int @.a }
(A)

> A.new(a => [1,2,3])
A.new(a => Array[Int].new(1, 2, 3))

> A.new(a => [1,2,'x'])
Type check failed in assignment to @!a; expected Int but got Str ("x")
  in block <unit> at <unknown file> line 1

编辑 1

根据文档,这有效

> sub f(Int @a) {1}
&f

> my Int @a = 1,2,3 # or (1,2,3), or [1,2,3]
> f(@a)
1

但是如果我Int在声明中省略,@a我会回到之前报告的错误。如前所述,我无法f在匿名数组上运行,使用f([1,2,3]).

回答

我认为主要的误解是,my Int @a = 1,2,3并且[1,2,3]在某种程度上是等价的。他们不是。第一种情况定义了一个接受Int值的数组。第二种情况定义了一个可以接受任何东西的数组,并且恰好在其中包含Int值。

我会尽量覆盖你试过了,为什么他们没有工作的所有版本,并可能如何工作。我将使用一个裸dd作为到达函数体的证据。

#1

sub f(Int @a) { dd }
f([1,2,3])

这不起作用,因为签名接受对其容器描述符PositionalInt约束的a 。签名绑定仅查看参数的约束而不查看值。观察:

my Int @a; say @a.of;   # (Int)
say [1,2,3].of;         # (Mu)
say Mu ~~ Int;          # False

这种方法没有解决方案,因为没有[ ]生成ArrayInt约束的语法。

#2

sub f(@a where *.all ~~ Int) { dd }

这是非常接近的,但使用*是不正确的。我不确定这是否是一个错误。

您发现这些解决方案也有效:

sub f(@a where { @a.all ~~ Int }) { dd }
sub f(@a where { $_.all ~~ Int }) { dd }

幸运的是,你不能有实际指定明确的块。这也有效:

sub f(@a where @a.all ~~ Int) { dd }
sub f(@a where $_.all ~~ Int) { dd }

除了您找到的@a.all$_.all解决方案之外,还有第三个解决方案:将*!

sub f(@a where .all ~~ Int) { dd }

#3

class A { has Int @.a }
A.new(a => [1,2,3])

这与签名绑定不同。有效地在.new你做的是:

@!a = [1,2,3]

这是有效的,因为Int您指定的数组中只有值。正如你所展示的,如果里面还有其他东西,它就会失败。但这与:

my Int @a = [1,2,"foo"]

失败。


以上是如何对Raku函数的数组参数的条目进行类型约束?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>