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 ...
第一个循环将值绑定到$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 `->`
代码有点短。惯用代码可能会更短一些,删除:
Raku 的印记是不变的。下面是两张表格,提供了 Perl 的 sigil 变化与 Raku 的 sigil invariance 的一目了然的比较。
为什么要打扰印记?
所有印记变体直接对应于将“类型”信息嵌入到人类、语言和编译器可见的标识符名称中:
foo告诉 Raku 功能应该根据数据的运行时类型来决定在单数和复数对数据的操作方式之间进行选择。
$foo
告诉 Raku 选择奇异的行为。例如,一个值可能是List
包含许多值的 a,但它的奇异性质反而被强调了。
&foo
类型检查绑定或分配的值是否Callable
发挥作用。
@foo
告诉 Raku 选择Iterable
行为。还要键入检查绑定值是否Positional
起作用。可以绑定a List
or ,但尝试绑定or a会产生类型错误。Array
42
Hash
%foo
告诉 Raku 选择Iterable
行为。还要键入检查绑定值是否Associative
起作用。可以绑定a Pair
or ,但尝试绑定or a会产生类型错误。Bag
42
List
接下来,我将考虑您对每个印记替代方案的问题。
削减印记
重复你的例子,但这次“削减”印记:
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
这些几乎完全按预期工作:
say arr[0]; # 1
say lst[1]; # 2
say hash<a>; # 1
say hash{'b'}; # 2
func.('hello'); # hello
请参阅$ vs &
下面的内容,了解为什么func.(...)
不只是func(...)
. 最后一个 nosigil 案例没有什么影响,因为在 Raku 中,通常会这样写道:
sub func (\foo) { say foo }
func('hello'); # hello
标志被削减的标识符是SSA 形式。也就是说,它们在编译时永久绑定到它们的数据。值类型数据是不可变的。引用也是不可变的(尽管它引用的数据可以更改),因此例如,如果它是一个数组,它将保持相同的数组。
(请参阅禁止重新绑定无符号变量是否有目的或好处?进一步讨论。)
$foo
而不是@foo
?
乐支持:
以上三个功能单独使用,也可以一起使用。但是,尽管 Raku 不尝试以其他方式监管这些功能是合适的,但需要遵守规则以避免出现问题。最简单的方法是在重要时使用正确的印记,如下所述。
假设infinite
是一个无限的惰性列表,它False
返回.is-lazy
:
my $foo = infinite;
say $foo[10]; # displays 11th element
my @foo = infinite;
前两行工作正常。第三个挂起,试图将无限数量的元素复制到@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 ; # abc <-- Treat as plural thing
.say for list ; # abc <-- Go by bound value, not sigil
上面选择的 sigil 只是表明您希望语言结构和读者默认采用的视图。如果您愿意,您可以自行反转:
.say for @$list ; # abc
.say for $@list ; # [a b c]
.say for $(list) # (a b c)
分配不同:
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; # []
对@
变量的赋值会“啜饮”所有剩余的参数。(与调用标量语义:=
之类的元操作绑定Z=
,即不要啜饮。)
我们在这里看到另一个区别;分配给$
变量将保留 a List
,List
但分配给@
变量会将其值“啜饮”到变量绑定到的任何容器@
中(默认情况下为 an 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
$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
赋值和字符串插值也以类似于@
.
$foo
而不是&foo
?
本节只是为了完整性。它只显示了一个使用$
. 我刚刚弥补了这个答案——我不记得看到有人使用它。
与其他 sigil 替代品一样,主要区别在于您是否想要强调Callable
可调用对象的性质。
作为设置,请注意sub
Raku 中的声明声明了一个带有符号的相应常量标识符&
:
sub foo (--> Int) { 42 }
say foo; # 42
say &foo.signature; # ( --> Int)
&foo = 99; # Cannot modify an immutable Sub...
这意味着如果您使用 sigil 声明一个可变的例程变量,您可以在没有&
sigil 的情况下调用它:
my &bar = { 99 }
say bar; # 99
&bar = { 100 }
say bar; # 100
如果您想声明一个可变的例程变量并且不允许在没有 sigil 的情况下轻松调用它,您可以$
改为声明它:
my Callable $baz = { 101 }
say baz; # Undeclared routine: baz
say $baz(); # 101 <-- Need both sigil and parens
顺便说一句,这就是你得到的原因:
my \func = -> \foo { say foo }
func('hello'); # Variable '&func' is not declared
参考文字
Q2:我们是在再次处理类似 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
你说的是那种东西吗?
取消引用文字
postcircumfix:< [ ] >
被声明为一堆(应该)Positional
在其左参数上应用一致的索引协议的多子。
同样的故事适用于postcircumfix:< { } >
and postcircumfix:« < > »
,但相关的角色/协议是Associative
一致的索引。
类似的故事也适用于postcircumfix:< ( ) >
和Callable
。