是否可以在运行时内省标量的范围?

Is it possible to introspect into the scope of a Scalar at runtime?

如果我有以下变量

my $a    = 0;
my $*b   = 1;
state $c = 2;
our $d   = 3;

我可以很容易地确定 $*b 是动态的,但 $a 不是以下代码

say $a.VAR.dynamic;
say $*b.VAR.dynamic;

有什么方法可以类似地确定 $c 是状态变量而 $d 是包范围变量? (我知道我可以在每个变量声明上使用 will 特性来做到这一点,但我希望有一种方法不需要注释每个声明。也许有 ::(...) 插值?)

对于包范围变量,不太难:

our $foo = 'bar';
say $foo.VAR.name ∈ OUR::.keys

我们使用 OUR pseudopackage 的地方。但是,没有 STATE 伪包这样的东西。它们显然出现在 LEXICAL 伪包中,但我找不到检查它们是否为状态变量的方法。对不起。

据我所知,无法识别 state 变量。像任何词汇一样,它存在于 lepad 中。唯一不同的是,它会在第一次进入范围时有效地生成代码来进行初始化。

正如 Elizabeth Mattijsen 正确指出的那样,目前无法在 运行 时查看变量是否为 state 变量。 ...在 运行 时间至少 技术上

然而,正如 Jonathan Worthington 的评论所暗示的那样, 可以在编译时检查它。而且,如果没有深层元编程恶作剧,变量是否是 state 变量在编译时后是不可变的。而且,当然,可以在编译时记下一些信息,然后在 运行 时使用它。

因此,可以在 运行 时知道一个变量是否是一个 state 变量(编译时)代码如下,它提供了一个 list-state-vars 列出函数中所有 state 变量的特征:

multi trait_mod:<is>(Sub \f, :$list-state-vars) {
    use nqp;
    given f.^attributes.first({.name eq '@!compstuff'}).get_value(f)[0] {
       say .list[0].list.grep({try .decl ~~ 'statevar'}).map({.name});
    }
};

这段代码在 QAST 的 Rakudo 实现细节上显然很漂亮 fragile/dependent。希望使用 RAST 这会容易得多,但这种基本方法已经可行,与此同时,guide to QAST hacking 是此类元编程的有用资源。