反省捕获的更好方法
A better way to introspect a capture
我想测试签名中第一个对象的类型。以下显示了我发现的一些可行方法。但是为什么智能匹配类型(以下 3 个测试中的第 2 个)不起作用?
有没有比对 Type 的字符串等价物进行字符串化和测试更好的方法?
(以下是我正在处理的用例)
raku -e "sub a( |c ) { say so |c[0].WHAT.raku ~~ /'Rat'/, so |c[0].WHAT ~~ Rat, so |c[0].^name ~~ /'Rat'/ };a(3/2);a(2)"
TrueFalseTrue
FalseFalseFalse
# OUTPUT:
#TrueFalseTrue
#FalseFalseFalse
我正在写一个proto sub handle
,大多数订阅者都有相似的签名,例如。 multi sub handle( Pod $node, MyObj $p, Int $level --> Str)
所以大多数多子根据 $node 中的内容做不同的事情。但是,如何处理使用 Nil
或纯字符串调用 handle
的情况。我正在考虑
proto handle(|c) {
if |c[0].^name ~~ /'Str'/ { # code for string }
else { {*} }
}
您可以简单地智能匹配一个类型:
raku -e "sub a( *@c ) { say @c[0] ~~ Rat };a(3/2);a(2)"
True
False
另外我这里用的是slurpy and not a capture, which is another alternative. Any way, with a single argument you're probably better off using type captures
raku -e "sub a( ::T $ ) { say ::T ~~ Rat };a(3/2);a(2)"
True
False
A better way to introspect ...
一般来说,在任何编程语言中做任何事情的更好方法是不要反省,如果你能避免的话。
一般来说,在 Raku 中,您可以避免手动自省。请参阅本答案末尾的 内省 部分以进一步讨论。
... a capture
获取捕获内省功能的最佳工具是使用签名。这是他们人生的主要目的。
I want to test the type of the first object in a signature
使用签名:
proto handle(|) {*}
multi handle( Pod $node ) { ... }
multi handle( Str $string ) { ... }
multi handle( Nil ) { ... }
The following shows some ways I have found that work.
虽然他们按照您的意愿行事,但他们实际上忽略了 Raku 的所有标志性功能。他们将签名简化为仅将捕获绑定为单个结构;然后在例程的主体中对该捕获进行手动内省。
使用签名几乎总是有一种更简单更好的方法来完成这些事情。
why does [|c[0].WHAT ~~ Rat
, with c[0] == 3/2
] not work?
我会先进行简化,然后以您的代码的作用结束:
say 3/2 ~~ Rat; # True
say (3/2) ~~ Rat; # True
say (3/2).WHAT ~~ Rat; # True
say |((3/2).WHAT ~~ Rat); # True
say (|(3/2).WHAT) ~~ Rat; # False
say |(3/2).WHAT ~~ Rat; # False
最后一种情况是因为|
比~~
有更高的precedence。
Is there a better way than stringifying and testing for the string equivalent of the Type?
天哪,是的。
使用类型,卢克。
(在您的用例中,请使用签名。)
自省
与手动检查例程主体中传入数据的代码相比,适当使用签名通常会:
读得更好;
生成更好的底层代码;
在 编译 阶段进行部分或全部评估。
如果一种语言及其编译器通过提供特定功能(例如签名)来处理用例,那么使用该功能而不是内省通常会带来上述三个好处。
Languages/compilers 可以分为四类,即:
不要做或允许任何内省;
允许 编译器 自省,但不允许 devs;
允许编译器和开发人员进行自省,但至少对开发人员而言,这是最后的手段;
启用并鼓励开发人员进行内省。
乐(do)属于第三类。在此 SO 的上下文中,签名是主要功能,几乎消除了开发人员手动自省的任何需要。
您可以从签名中的 Capture 中提取内容。
# ( |C ( ::Type $a, +@b ) )
proto handle( | ( ::Type, +@ ) ) {
if Type ~~ Str {
…
} else {
{*}
}
}
基本上,参数前的 ::Foo
(或代替它)类似于该参数上的 .WHAT
。
它也可用作类型描述符。
sub foo ( ::Type $a ) {
my Type $b = $a;
}
根据名称比较类型是一个非常糟糕的主意。
my $a = anon class Foo { has $.a }
my $b = anon class Foo { has $.b }
say $a.WHAT =:= $b.WHAT; # False
say $a.^name eq $b.^name; # True
对于Raku来说,两种类型碰巧重名完全是巧合。
如果您确实使用这些名称,您的代码将混淆实际情况。
我想测试签名中第一个对象的类型。以下显示了我发现的一些可行方法。但是为什么智能匹配类型(以下 3 个测试中的第 2 个)不起作用? 有没有比对 Type 的字符串等价物进行字符串化和测试更好的方法? (以下是我正在处理的用例)
raku -e "sub a( |c ) { say so |c[0].WHAT.raku ~~ /'Rat'/, so |c[0].WHAT ~~ Rat, so |c[0].^name ~~ /'Rat'/ };a(3/2);a(2)"
TrueFalseTrue
FalseFalseFalse
# OUTPUT:
#TrueFalseTrue
#FalseFalseFalse
我正在写一个proto sub handle
,大多数订阅者都有相似的签名,例如。 multi sub handle( Pod $node, MyObj $p, Int $level --> Str)
所以大多数多子根据 $node 中的内容做不同的事情。但是,如何处理使用 Nil
或纯字符串调用 handle
的情况。我正在考虑
proto handle(|c) {
if |c[0].^name ~~ /'Str'/ { # code for string }
else { {*} }
}
您可以简单地智能匹配一个类型:
raku -e "sub a( *@c ) { say @c[0] ~~ Rat };a(3/2);a(2)"
True
False
另外我这里用的是slurpy and not a capture, which is another alternative. Any way, with a single argument you're probably better off using type captures
raku -e "sub a( ::T $ ) { say ::T ~~ Rat };a(3/2);a(2)"
True
False
A better way to introspect ...
一般来说,在任何编程语言中做任何事情的更好方法是不要反省,如果你能避免的话。
一般来说,在 Raku 中,您可以避免手动自省。请参阅本答案末尾的 内省 部分以进一步讨论。
... a capture
获取捕获内省功能的最佳工具是使用签名。这是他们人生的主要目的。
I want to test the type of the first object in a signature
使用签名:
proto handle(|) {*}
multi handle( Pod $node ) { ... }
multi handle( Str $string ) { ... }
multi handle( Nil ) { ... }
The following shows some ways I have found that work.
虽然他们按照您的意愿行事,但他们实际上忽略了 Raku 的所有标志性功能。他们将签名简化为仅将捕获绑定为单个结构;然后在例程的主体中对该捕获进行手动内省。
使用签名几乎总是有一种更简单更好的方法来完成这些事情。
why does [
|c[0].WHAT ~~ Rat
, withc[0] == 3/2
] not work?
我会先进行简化,然后以您的代码的作用结束:
say 3/2 ~~ Rat; # True
say (3/2) ~~ Rat; # True
say (3/2).WHAT ~~ Rat; # True
say |((3/2).WHAT ~~ Rat); # True
say (|(3/2).WHAT) ~~ Rat; # False
say |(3/2).WHAT ~~ Rat; # False
最后一种情况是因为|
比~~
有更高的precedence。
Is there a better way than stringifying and testing for the string equivalent of the Type?
天哪,是的。
使用类型,卢克。
(在您的用例中,请使用签名。)
自省
与手动检查例程主体中传入数据的代码相比,适当使用签名通常会:
读得更好;
生成更好的底层代码;
在 编译 阶段进行部分或全部评估。
如果一种语言及其编译器通过提供特定功能(例如签名)来处理用例,那么使用该功能而不是内省通常会带来上述三个好处。
Languages/compilers 可以分为四类,即:
不要做或允许任何内省;
允许 编译器 自省,但不允许 devs;
允许编译器和开发人员进行自省,但至少对开发人员而言,这是最后的手段;
启用并鼓励开发人员进行内省。
乐(do)属于第三类。在此 SO 的上下文中,签名是主要功能,几乎消除了开发人员手动自省的任何需要。
您可以从签名中的 Capture 中提取内容。
# ( |C ( ::Type $a, +@b ) )
proto handle( | ( ::Type, +@ ) ) {
if Type ~~ Str {
…
} else {
{*}
}
}
基本上,参数前的 ::Foo
(或代替它)类似于该参数上的 .WHAT
。
它也可用作类型描述符。
sub foo ( ::Type $a ) {
my Type $b = $a;
}
根据名称比较类型是一个非常糟糕的主意。
my $a = anon class Foo { has $.a }
my $b = anon class Foo { has $.b }
say $a.WHAT =:= $b.WHAT; # False
say $a.^name eq $b.^name; # True
对于Raku来说,两种类型碰巧重名完全是巧合。
如果您确实使用这些名称,您的代码将混淆实际情况。