意外的哈希扁平化

Unexpected Hash flattening

我正在寻找为什么这两个数据结构不相等的解释:

$ perl6 -e 'use Test; is-deeply [ { a => "b" } ], [ { a => "b" }, ];'
not ok 1 -
# Failed test at -e line 1
# expected: $[{:a("b")},]
#      got: $[:a("b")]

哈希和数组中的尾随逗号与 P5 中一样没有意义:

$ perl6 -e '[ 1 ].elems.say; [ 1, ].elems.say'
1
1

但是如果没有它,哈希会以某种方式丢失,并且会被压平成对数组:

$ perl6 -e '[ { a => "b", c => "d" } ].elems.say;'
2

我怀疑这里适用一些 Great List Refactor 法则,但我想获得更详细的解释以理解这种扁平化背后的逻辑。

Trailing comma in Hashes and Arrays is meaningless just like in P5

不,不是没有意义:

(1 ).WHAT.say ; # (Int)
(1,).WHAT.say ; # (List)

Great List Refactor 中的重大简化是切换到 the single argument rule 以迭代功能1。也就是说,像 for 或数组和散列组合器(和下标)这样的特性总是有一个参数。这确实是您的原始示例所发生的事情。

单个参数可能是——通常是——一个值列表,甚至可能是一个列表列表等,但顶级列表仍然是迭代功能的单个参数。

如果迭代功能的单个参数执行 Iterable role (for example lists, arrays, and hashes), then it's iterated. (This is an imprecise formulation; see 到 "When does for call the iterator method?" 以获得更精确的参数。)

所以这里要注意的关于那个额外逗号的关键是,如果单个参数 而不是 则起到 Iterable 的作用,例如 1 ,那么最终结果就好像参数是一个只包含一个值的列表(即 1,):

.perl.say for {:a("b")}   ; # :a("b")     Iterable Hash was iterated
.perl.say for {:a("b")} , ; # {:a("b")}   Iterable List was iterated
.perl.say for 1           ; # 1           Non Iterable 1 left as is
.perl.say for 1 ,         ; # 1           Iterable List was iterated

典型的方式"to preserve structure [other than] using trailing comma when single element list is declared"(见下面的评论),即 stop 单个 Iterable 值像往常一样迭代,是通过 item-用 $ 对其进行化处理:

my @t = [ $[ $[ "a" ] ] ];
@t.push: "b";
@t.perl.say; # [[["a"],], "b"]

1for的情况下,迭代用于获取要传递给某些代码的值;在作曲家的情况下,使值成为正在构建的 array/hash 的元素;在下标的情况下获取索引切片;以此类推其他迭代功能。