Raku 中的参数化类型,如何使用 运行 时间值作为参数
Parametrized types in Raku, how to use run time values as parameters
我想为 Raku 创建一些 parametrized types;基本上,我想创建一些不同的 类,其主要区别在于其属性之一的值范围;例如,类 代表建筑物的类型,我想为 3 层或任何其他楼层数的建筑物设置不同的 类。
所以这是我能想到的最好的:
subset Two-Tops of UInt where * <=2;
subset Three-Tops of UInt where * <=3;
role Zipi[ ::Capper ] {
has Capper $.floor;
}
class Capped-at-three does Zipi[Three-Tops] {}
my $capped = Capped-at-three.new( floor => 2 );
say $capped.raku;
这显然是不切实际的,因为您需要处理许多不同数量的楼层(格拉纳达不是这里,我认为他们最多有 10 层,但好吧...)。这里的问题基本上是你需要在编译时获得子集的信息,所以除非你对参数的任何值使用 macros (still experimental), there's no way you can use any kind of variable. So can you think of a practical way of defining this kind of curried roles?
我尝试使用匿名 where
子句,但同样无济于事,但我找到了问题所在:where
子句显然被 BUILD
方法忽略了。我不确定是不是因为它有绕过 where
子句的直接访问(通过 $!floor
),或者是否发生了其他奇怪的事情(可能是后者,我一般得到 Nil
如果我试图在 where
子句中使用参数化值。
尽管如此,这应该能很好地工作,包括提供有用的错误消息:
role Zipi[$condition] {
has $.floor;
submethod BUILD(:$floor, |c) {
die "Invalid floor number."
unless $floor ~~ $condition;
$!floor = $floor;
}
}
如果您可以假设楼层始终为 0 .. x
或 x .. y
,并且可以提供更有用的错误消息,您会发现修改起来很容易。
我的 MOP 印章非常有限,下面的内容看起来很丑陋,但它有效,并且可能是朝着正确方向迈出的一步。
我做了什么:
通过 MOP 动态构造了一个 10,000 subset
s 的数组。
时间通过 BEGIN
.
将它们的构建时间转移到编译时间
使用了数组中的适当元素来参数化角色。
my @max-floors-checkers;
BEGIN {
@max-floors-checkers = do for ^10_000 -> \floors {
Metamodel::SubsetHOW.new_type:
refinee => UInt,
refinement => { $^floors <= floors }
}
}
role BuildingCategory[ ::MaxFloorsCheck ] { has MaxFloorsCheck $.floors }
class Capped-at-three does BuildingCategory[ @max-floors-checkers[3] ] {}
my $capped3 = Capped-at-three.new( floors => 2 );
say $capped3.raku; # Capped-at-three.new(floors => 2
my $capped4 = Capped-at-three.new( floors => 4 ); # Type check failed
实际上,与我之前所说的不同,您可以在 where 子句中使用条件没有问题,您只需要将它们括在大括号中即可:
role Zipi[$condition] {
has $.floor is rw where {$_ ~~ $condition}
method foo($x) { $!floor = $x }
}
class A does Zipi[2 < * < 5] {
method bar($x) { $.floor = $x }
}
#my $a = A.new( floor => 10); # error
my $a = A.new( floor => 4); # OK
#$a.foo(10); # error
$a.foo(3); # OK
#$a.bar(0); # error
$a.bar(4); # OK
#$a.floor = 9; # error
$a.floor = 3; # OK
这应该涵盖所有作业类型
涵盖案例的 nanswer reader 知道 Java 但不知道 Raku。
Collection<String> coll = new LinkedList<String>();
parametrized types for Raku
链接的 Java 示例是:
The instantiation of a generic type with actual type arguments is called a parameterized type. Example (of a parameterized type):
Collection<String> coll = new LinkedList<String>();
一个合理的 Raku 类比是:
my Positional[Str] \coll = Array[Str].new;
Positional
type is a parameterizable role。角色指定接口 and/or 类型的部分实现。我相信 Raku 的 Positional
与 Java 的 Collection
非常相似,它用于此 nanswer 的目的。
Array
type is a parameterizable class。它指定了一个符合 Positional
角色的数据结构。它不是链接列表,但足以满足此 nanswer 的目的。
我想为 Raku 创建一些 parametrized types;基本上,我想创建一些不同的 类,其主要区别在于其属性之一的值范围;例如,类 代表建筑物的类型,我想为 3 层或任何其他楼层数的建筑物设置不同的 类。 所以这是我能想到的最好的:
subset Two-Tops of UInt where * <=2;
subset Three-Tops of UInt where * <=3;
role Zipi[ ::Capper ] {
has Capper $.floor;
}
class Capped-at-three does Zipi[Three-Tops] {}
my $capped = Capped-at-three.new( floor => 2 );
say $capped.raku;
这显然是不切实际的,因为您需要处理许多不同数量的楼层(格拉纳达不是这里,我认为他们最多有 10 层,但好吧...)。这里的问题基本上是你需要在编译时获得子集的信息,所以除非你对参数的任何值使用 macros (still experimental), there's no way you can use any kind of variable. So can you think of a practical way of defining this kind of curried roles?
我尝试使用匿名 where
子句,但同样无济于事,但我找到了问题所在:where
子句显然被 BUILD
方法忽略了。我不确定是不是因为它有绕过 where
子句的直接访问(通过 $!floor
),或者是否发生了其他奇怪的事情(可能是后者,我一般得到 Nil
如果我试图在 where
子句中使用参数化值。
尽管如此,这应该能很好地工作,包括提供有用的错误消息:
role Zipi[$condition] {
has $.floor;
submethod BUILD(:$floor, |c) {
die "Invalid floor number."
unless $floor ~~ $condition;
$!floor = $floor;
}
}
如果您可以假设楼层始终为 0 .. x
或 x .. y
,并且可以提供更有用的错误消息,您会发现修改起来很容易。
我的 MOP 印章非常有限,下面的内容看起来很丑陋,但它有效,并且可能是朝着正确方向迈出的一步。
我做了什么:
通过 MOP 动态构造了一个 10,000
subset
s 的数组。时间通过
将它们的构建时间转移到编译时间BEGIN
.使用了数组中的适当元素来参数化角色。
my @max-floors-checkers;
BEGIN {
@max-floors-checkers = do for ^10_000 -> \floors {
Metamodel::SubsetHOW.new_type:
refinee => UInt,
refinement => { $^floors <= floors }
}
}
role BuildingCategory[ ::MaxFloorsCheck ] { has MaxFloorsCheck $.floors }
class Capped-at-three does BuildingCategory[ @max-floors-checkers[3] ] {}
my $capped3 = Capped-at-three.new( floors => 2 );
say $capped3.raku; # Capped-at-three.new(floors => 2
my $capped4 = Capped-at-three.new( floors => 4 ); # Type check failed
实际上,与我之前所说的不同,您可以在 where 子句中使用条件没有问题,您只需要将它们括在大括号中即可:
role Zipi[$condition] {
has $.floor is rw where {$_ ~~ $condition}
method foo($x) { $!floor = $x }
}
class A does Zipi[2 < * < 5] {
method bar($x) { $.floor = $x }
}
#my $a = A.new( floor => 10); # error
my $a = A.new( floor => 4); # OK
#$a.foo(10); # error
$a.foo(3); # OK
#$a.bar(0); # error
$a.bar(4); # OK
#$a.floor = 9; # error
$a.floor = 3; # OK
这应该涵盖所有作业类型
涵盖案例的 nanswer reader 知道 Java 但不知道 Raku。
Collection<String> coll = new LinkedList<String>();
parametrized types for Raku
链接的 Java 示例是:
The instantiation of a generic type with actual type arguments is called a parameterized type. Example (of a parameterized type):
Collection<String> coll = new LinkedList<String>();
一个合理的 Raku 类比是:
my Positional[Str] \coll = Array[Str].new;
Positional
type is a parameterizable role。角色指定接口 and/or 类型的部分实现。我相信 Raku 的 Positional
与 Java 的 Collection
非常相似,它用于此 nanswer 的目的。
Array
type is a parameterizable class。它指定了一个符合 Positional
角色的数据结构。它不是链接列表,但足以满足此 nanswer 的目的。