将标量绑定到无符号变量 (Perl 6)

Binding a scalar to a sigilless variable (Perl 6)

首先让我说我明白我在标题中问的是可疑的做法(如所解释的),但我对所涉及的语法缺乏理解。

当我第一次尝试将标量绑定到无符号符号时,我这样做了:

my \a = $(3);

认为 $(...) 会将 Int 3 打包在标量中(正如 documentation 中似乎建议的那样),然后将其绑定到符号 a。但这似乎不起作用:找不到标量(a.VAR.WHAT returns(Int),而不是(标量))。

在 above-referenced post 中,raiph 提到可以使用不同的语法执行所需的绑定:

my \a = $ = 3;

有效。鉴于结果,我怀疑该陈述可以等效地表述为:my \a = (my $ = 3),但我可以理解。

这就留下了一个问题:为什么 $(...) 的尝试不起作用,它做了什么?

Sigilless variables are not actually variables, they are more of an alias, that is, they are not containers 但绑定到他们在右侧获得的值。

my \a = $(3); 
say a.WHAT; # OUTPUT: «(Int)␤»
say a.VAR.WHAT; # OUTPUT: «(Int)␤»

在这里,通过执行 $(3),您实际上是将已经在标量上下文中的内容放入标量上下文中:

my \a = 3; say a.WHAT; say a.VAR.WHAT; # OUTPUT: «(Int)␤(Int)␤»

但是,您问题中的第二种形式有所不同。您正在绑定到一个匿名变量,它是一个容器:

my \a = $ = 3; 
say a.WHAT;    # OUTPUT: «(Int)␤»
say a.VAR.WHAT;# OUTPUT: «(Scalar)␤»

第一种情况,a是3的别名(或者$(3),是一样的);第二个,a$的别名,是一个容器,其值为3。最后一种情况相当于:

 my $anon = 3; say $anon.WHAT; say $anon.VAR.WHAT; # OUTPUT: «(Int)␤(Scalar)␤»

(如果您对如何改进文档有任何建议,我很乐意跟进)

$(…) 所做的是将值转换为 item
(标量变量 ($a) 中的值也被标记为一个项目)

say flat (1,2,      (3,4)  );
# (1 2 3 4)

say flat (1,2,    $((3,4)) );
# (1 2 (3 4))

say flat (1,2, item((3,4)) );
# (1 2 (3 4))

基本上它是为了防止值变平。它存在的原因是 Perl 6 不像大多数其他语言那样扁平化列表,有时您需要对扁平化进行更多控制。


以下只是做你想让它做的事

my \a = $ = 3;

$ 是匿名 state 变量。

my \a = (state $) = 3;

当您多次 运行 相同的代码时,问题就会出现。

sub foo ( $init ) {
  my \a = $ = $init; # my \a = (state $) = $init;

  (^10).map: {
    sleep 0.1;
    ++a
  }
}

.say for await (start foo(0)), (start foo(42));
# (43 44 45 46 47 48 49 50 51 52)
# (53 54 55 56 57 58 59 60 61 62)

# If foo(42) beat out foo(0) instead it would result in:
# (1 2 3 4 5 6 7 8 9 10)
# (11 12 13 14 15 16 17 18 19 20)

请注意,变量在调用之间共享。
第一个 Promise 在 sleep 调用处停止,然后第二个 Promise 在第一个 运行s ++a.

之前设置状态变量

如果您改用 my $,它现在可以正常工作。

sub foo ( $init ) {
  my \a = my $ = $init;

  (^10).map: {
    sleep 0.1;
    ++a
  }
}

.say for await (start foo(0)), (start foo(42));
# (1 2 3 4 5 6 7 8 9 10)
# (43 44 45 46 47 48 49 50 51 52)

事实是无符号“变量”并不是真正的变量(它们不会变化),它们更类似于词法范围的(非)常量。

constant \foo = (1..10).pick; # only pick one value and never change it

say foo;
for ^5 {
  my \foo = (1..10).pick;     # pick a new one each time through

  say foo;
}

基本上它们的全部要点是尽可能接近指代您分配给它的值。 (Static Single Assignment)

# these work basically the same
-> \a        {…}
-> \a is raw {…}
-> $a is raw {…}

# as do these
my \a  = $i;
my \a := $i;
my $a := $i;

注意上面我写了以下内容:

my \a = (state $) = 3;

通常在状态变量的声明中,赋值仅在代码第一次获取时发生 运行。 Bare $ 没有这样的声明,所以我不得不通过将声明放在括号中来防止这种行为。

# bare $
for (5 ... 1) {
  my \a =        $  = $_; # set each time through the loop

  say a *= 2; # 15 12 9 6 3
}

# state in parens
for (5 ... 1) {
  my \a = (state $) = $_; # set each time through the loop

  say a *= 2; # 15 12 9 6 3
}

# normal state declaration
for (5 ... 1) {
  my \a =  state $  = $_; # set it only on the first time through the loop

  say a *= 2; # 15 45 135 405 1215
}