【发布时间】:2020-11-15 12:32:48
【问题描述】:
我非常感谢 Raku 的 &?BLOCK 变量——它让您可以在一个未命名的块内进行递归,这可能非常强大。例如,这是一个简单的内联匿名阶乘函数:
{ when $_ ≤ 1 { 1 };
$_ × &?BLOCK($_ - 1) }(5) # OUTPUT: «120»
但是,在更复杂的情况下使用它时,我有一些疑问。考虑这段代码:
{ say "Part 1:";
my $a = 1;
print ' var one: '; dd $a;
print ' block one: '; dd &?BLOCK ;
{
my $a = 2;
print ' var two: '; dd $a;
print ' outer var: '; dd $OUTER::a;
print ' block two: '; dd &?BLOCK;
print "outer block: "; dd &?OUTER::BLOCK
}
say "\nPart 2:";
print ' block one: '; dd &?BLOCK;
print 'postfix for: '; dd &?BLOCK for (1);
print ' prefix for: '; for (1) { dd &?BLOCK }
};
产生这个输出(我已经缩短了块 ID):
Part 1:
var one: Int $a = 1
block one: -> ;; $_? is raw = OUTER::<$_> { #`(Block|…6696) ... }
var two: Int $a = 2
outer var: Int $a = 1
block two: -> ;; $_? is raw = OUTER::<$_> { #`(Block|…8496) ... }
outer block: -> ;; $_? is raw = OUTER::<$_> { #`(Block|…8496) ... }
Part 2:
block one: -> ;; $_? is raw = OUTER::<$_> { #`(Block|…6696) ... }
postfix for: -> ;; $_ is raw { #`(Block|…9000) ... }
prefix for: -> ;; $_ is raw { #`(Block|…9360) ... }
这就是我不明白的地方:为什么&?OUTER::BLOCK 引用(基于其 ID)阻止第二个而不是阻止一个?正确使用 OUTER 和 $a 会导致它引用外部范围,但同样的事情不适用于 &?BLOCK。 OUTER 不能与&?BLOCK 一起使用吗?如果没有,有没有办法从内部块访问外部块? (我知道我可以将&?BLOCK 分配给外部块中的命名变量,然后在内部块中访问该变量。我认为这是一种解决方法,但不是完整的解决方案,因为它牺牲了引用未命名块的能力,这就是&?BLOCK 的大部分力量的来源。)
其次,我对第 2 部分感到非常困惑。我明白为什么前缀 for 后面的 &?BLOCK 指的是内部块。但是为什么 also 的后缀前面的&?BLOCK 指的是它自己的块?是否在 for 语句的主体周围隐式创建了一个块?我的理解是后缀形式在很大程度上是有用的,因为它们确实不需要块。不对吗?
最后,为什么有些块有OUTER::<$_> 而其他块没有?我对第 2 块感到特别困惑,它不是最外面的块。
提前感谢您提供的任何帮助! (如果上面显示的任何代码行为表明存在 Rakudo 错误,我很乐意将其写为问题。)
【问题讨论】:
标签: metaprogramming raku compile-time rakudo