将非标量分配给标量有什么好处?

Ele*_*fee 12 sigils raku

我有时会看到(对我而言)在变量前面使用错误符号的代码

my $arr  = [1, 2, 3, 4, 5];      # an array
my $lst  = (1, 2, 3, 4, 5);      # a list
my $hash = {a => '1', b => '2'}; # a hash
my $func = -> $foo { say $foo }; # a callable
Run Code Online (Sandbox Code Playgroud)

这一切都完全按预期工作

say $arr[0];    # 1
say $lst[1];    # 2
say $hash<a>;   # 1
say $hash{'b'}; # 2
$func('hello'); # hello
Run Code Online (Sandbox Code Playgroud)

Q1:为此使用标量容器有什么好处,而不仅仅是使用“正确”的容器?

我知道的Perl只让收藏店标量,要求之类的多维数组通过数组引用来完成,以[...]{...}为数组和散列引用分别文字。

为了扩展和澄清我在这里的意思,基本上有两种定义事物的方法,通过值和通过引用:

my $arr  = [1, 2, 3, 4, 5];      # an array
my $lst  = (1, 2, 3, 4, 5);      # a list
my $hash = {a => '1', b => '2'}; # a hash
my $func = -> $foo { say $foo }; # a callable
Run Code Online (Sandbox Code Playgroud)

这种疯狂背后的原因是 Perl 集合只真正接受标量,而引用就是如此。使用引用本质上是一种启用多维数组的方法。

TL;DR,区别在 Perl 中是有意义的,因为它们用于两个截然不同的目的。

问题 2:我们是再次处理类似 Perl 5 的引用文字,还是有其他东西在起作用?

rai*_*iph 10

TL;DR对于计算机和人类,因此 Raku 也是如此,非标量(复数)也是标量(单数)。(反之亦然。)例如, anArray既是复数事物(元素数组),又是单一事物 an Array。当您希望在句法和静态上强调数据最通用的奇异性质时,请使用$.

这是一个基于@sid_com++ 评论的开篇示例:

my @a = ( 1, 2 ), 42, { :a, :b }
for @a -> $b {say $b}            # (1 2)?42?{a => True, b => True}? 
for @a -> @b {say @b}            # (1 2)?Type check failed ...
Run Code Online (Sandbox Code Playgroud)

第一个循环将值绑定到$b。它是“容错的”,因为它接受任何值。第二个循环绑定到@b. 任何不做的值Positional发挥作用的导致类型检查失败。

我的 Raku 相当于你的 Perl 代码

这是您的 Perl 代码的 Raku 翻译:

my @arr = (1, 2, 3, 4);
my %hash = (1 => 2, 3 => 4); 

my $result1 = @arr[0];                          # <-- Invariant sigil
my $result2 = %hash{1};                         # <-- Invariant sigil

my $aref = [1, 2, 3, 4];
my $href = {1 => 2, 3 => 4};

my $aref2 = @arr;                               # <-- Drop `\`
my $href2 = %hash;                              # <-- Drop `\`

my $result3 = $aref[0];                         # <-- Drop `->`
my $result4 = $href{1};                         # <-- Drop `->`
Run Code Online (Sandbox Code Playgroud)

代码有点短。惯用代码可能会更短一些,删除:

  • ref变量。变量@foo 一个引用。甲[...]在术语(名词)位置一个Array参考文字。很少或根本不需要使用标量变量来显式存储引用。

  • 前几行中的括号;

  • 大多数右大括号后的分号是一行的最后一个代码;

Raku 的印记是不变的。这里有两个表提供了 Perl 的 sigil 变化与 Raku 的 sigil invariance 的简要比较

为什么要打扰印记?

所有的 sigil 变体都直接对应于将“类型”信息嵌入到对人类、语言和编译器可见的标识符名称中:

  • foo告诉 Raku 功能在数据操作的单数和复数方式之间进行选择应该根据数据的运行时类型来决定。

  • $foo告诉 Raku 选择单一行为。例如,一个值可能是一个List包含许多值的一个,但它的单一性反而被强调了。

  • &foo类型检查绑定或分配的值是否Callable起到了作用。

  • @foo告诉 Raku 选择Iterable行为。还要键入检查绑定值是否Positional起作用。A ListorArray可以绑定,但是尝试绑定到42or aHash会产生类型错误。

  • %foo告诉 Raku 选择Iterable行为。还要键入检查绑定值是否Associative起作用。A PairorBag可以绑定,但是尝试绑定到42or aList会产生类型错误。

接下来我将考虑您对每个印记替代方案的问题。

削减印记

重复你的例子,但这次“削减”标志:

my \arr  = [1, 2, 3, 4, 5];      # an array
my \lst  = (1, 2, 3, 4, 5);      # a list
my \hash = {a => '1', b => '2'}; # a hash
my \func = -> \foo { say foo };  # a callable
Run Code Online (Sandbox Code Playgroud)

这些几乎完全按预期工作:

say arr[0];     # 1
say lst[1];     # 2
say hash<a>;    # 1
say hash{'b'};  # 2
func.('hello'); # hello
Run Code Online (Sandbox Code Playgroud)

请参阅$ vs &下面的内容,了解为什么它func.(...)不仅仅是func(...). 最后一个 nosigil 案例无关紧要,因为在 Raku 中,人们通常会写道:

sub func (\foo) { say foo }
func('hello'); # hello
Run Code Online (Sandbox Code Playgroud)

带有斜线符号的标识符是SSA 形式。也就是说,它们在编译时永久绑定到它们的数据。值类型数据是不可变的。引用也是不可变的(尽管它引用的数据可以改变),例如,如果它是一个数组,它将保持相同的数组。

(请参阅禁止无符号变量重新绑定是否有目的或好处?进一步讨论。)

$foo而不是@foo

乐支持:

  • 懒惰的清单。(这可能非常有用。)

  • 一个布尔.is-lazy方法,指示列表赋值 ( @foo = ...) 应将已赋值的对象视为惰性对象还是急切对象。重要的是,允许惰性列表返回False。(这也非常有用。)

  • 无限懒惰列表。(还有一个非常有用的东西。)

以上三个功能单独有用,也可以一起使用。但是,虽然 Raku 不尝试以其他方式监管这些功能是适当的,但人们需要遵守规则以避免出现问题。最简单的方法是在重要时使用正确的印记,如下所述。

比方说infinite是一个无限懒惰列表回报False.is-lazy

my $foo = infinite;
say $foo[10];        # displays 11th element
my @foo = infinite;
Run Code Online (Sandbox Code Playgroud)

前两行工作正常。第三个挂起,试图将无限数量的元素复制到@foo.


是一件事还是多件事?当然,如果是列表,则两者兼而有之:

my $list = <a b c> ;
my @list = <a b c> ;
my \list = <a b c> ;
.say for $list ;      # (a b c)?   <-- Treat as one thing
.say for @list ;      # a?b?c?    <-- Treat as plural thing
.say for  list ;      # a?b?c?    <-- Go by bound value, not sigil
Run Code Online (Sandbox Code Playgroud)

上面的 sigil 选择只是表明您希望语言结构和读者在默认情况下采取什么观点。如果您愿意,您可以逆转自己:

.say for @$list ;     # a?b?c?
.say for $@list ;     # [a b c]?
.say for $(list)      # (a b c)?
Run Code Online (Sandbox Code Playgroud)

赋值不同:

my ($numbers, $letters) = (1, 2, 3), ('a', 'b', 'c');
say $numbers;                                            # (1 2 3)
say $letters;                                            # (a b c)
my (@numbers, @letters) = (1, 2, 3), ('a', 'b', 'c');
say @numbers;                                            # [(1 2 3) (a b c)]
say @letters;                                            # []
Run Code Online (Sandbox Code Playgroud)

分配给@变量“slurps”所有剩余的参数。(绑定:=和 metaops 之类的Z=调用标量语义,即不要。)

我们在这里看到了另一个不同之处;分配给一个$变量是要保持List一个List,但分配给一个@变量“吸食”其价值任何容器中的@变量绑定到(默认情况下,一个Array)。


一个小事情是字符串插值:

my $list := 1, 2;
my @list := 1, 2;
say "\$list = $list; \@list = @list"; # $list = 1 2; @list = @list
say "@list @list[] @list[1]";         # @list 1 2 2
Run Code Online (Sandbox Code Playgroud)

$foo而不是%foo

再说一遍,这是一件事还是多件事?如果是散列,则两者兼而有之。

my $hash = { :a, :b }
my %hash =   :a, :b ;
my \hash = { :a, :b }
.say for $hash ;      # {a => True, b => True}?   <-- By sorted keys
.say for %hash ;      # {b => True}?{a => True}?  <-- Random order
.say for  hash ;      # {a => True}?{b => True}?  <-- Random order
Run Code Online (Sandbox Code Playgroud)

赋值和字符串插值也以类似于 的方式不同@

$foo而不是&foo

本节只是为了完整性。它只显示了使用的一个原因$. 我刚刚为这个答案做出了补充 - 我不记得看到有人使用它。

与其他 sigil 替代方案一样,主要区别在于您是否想要强调Callable可调用对象的性质。

作为设置,请注意subRaku 中的声明声明了一个带有符号的相应常量标识符&

sub foo (--> Int) { 42 }
say foo;                     # 42
say &foo.signature;          # ( --> Int)
&foo = 99;                   # Cannot modify an immutable Sub...
Run Code Online (Sandbox Code Playgroud)

这意味着,如果你用&sigil声明一个可变的例程变量,你可以在没有sigil 的情况下调用它:

my &bar = { 99 }
say bar;                     # 99
&bar = { 100 }
say bar;                     # 100
Run Code Online (Sandbox Code Playgroud)

如果你想声明一个可变的常规变量,让它轻易称为无印记,你可以用它声明$,而不是:

my Callable $baz = { 101 }
say baz;                     # Undeclared routine: baz
say $baz();                  # 101   <-- Need both sigil and parens
Run Code Online (Sandbox Code Playgroud)

顺便说一句,这就是你得到的原因:

my \func = -> \foo { say foo }
func('hello');  # Variable '&func' is not declared
Run Code Online (Sandbox Code Playgroud)

引用文字

问题 2:我们是再次处理类似 Perl 5 的引用文字,还是有其他东西在起作用?

尽管有你的例子,了解 Perl(至少我在上个世纪做过),并思考过你写的东西,我仍然不清楚你在问什么。

许多编程语言都采用[...]术语(名词)位置作为对文字数组的引用。其他数据结构文字还有其他常见约定。这就是Raku所做的。

因此可以写:

my $structure =
[ 0, [ 99, [ ( 1, 2, 3), { key => [ 4, 5, | < a b >, c => 42 ] } ], ], ] ;

say $structure[1][1][1]<key>[4]<c> ; # 42
Run Code Online (Sandbox Code Playgroud)

你说的是那种事吗?

取消引用文字

postcircumfix:< [ ] >被声明为一堆多子(应该)Positional在它们的左参数上应用一致的索引协议。

  • 完成Positional角色工作的所有内置类型。

  • Positional扮演角色的用户定义类型应该可以工作,因为角色定义了必须由扮演角色的类型实现的类型化接口存根。

  • 但是鸭子打字也可以;如果类型实现了postcircumfix:< [ ] >它应该工作的接口的基础知识。

同样的故事适用于postcircumfix:< { } >and postcircumfix:« < > »,但相关的角色/协议是Associative一致的索引。

类似的故事也适用于postcircumfix:< ( ) >Callable


p6s*_*eve 5

已经有一些很好的答案了!为了进一步阅读这个一般主题,我可以建议Day 2 \xe2\x80\x93 Perl 6: Sigils, Variables, and Containers 吗?它帮助我理解了一些相关主题,例如作为容器的标量和decont op <>$我认为这些例子可以为和@/的相互作用提供更多的理论依据%管理按预期有效打包/解包数据结构的微妙之处

\n