我知道列表分配会使左侧变平:
my ($a, $b, $c);
($a, ($b, $c)) = (0, (1.0, 1.1), 2);
say "\$a: $a"; # OUTPUT: «$a: 0»
say "\$b: $b"; # OUTPUT: «$b: 1 1.1» <-- $b is *not* 1
say "\$c: $c"; # OUTPUT: «$c: 2» <-- $c is *not* 1.1
我也明白我们可以使用 :($a, ($b, $c)) := (0, (1.0, 1.1))
获得非扁平化行为。我不明白的是为什么在列表分配期间左侧会变平。这是两个问题:首先,这种扁平化行为如何与语言的其余部分相适应?其次,如果左侧是非展平的,自动展平是否允许任何不可能的行为?
关于第一个问题,我知道 Raku 历史上有很多自动展平行为。之前Great List Refactor , 类似
my @a = 1, (2, 3), 4
的表达式会自动展平它的右手边,导致数组 [1, 2, 3, 4]
;同样,map
和许多其他迭代结构会扁平化他们的论点。不过,在 GLR 之后,Raku 基本上不会在没有被告知的情况下将列表弄平。事实上,我想不出任何其他情况,如果没有 flat
,Raku 就会变平。 , .flat
, |
, 或 *@
以某种方式参与其中。 ( @_
创建一个隐式 *@
)。我是否遗漏了什么,或者列表分配中的 LHS 行为是否真的与 post-GLR 语义不一致?这种行为是历史上的怪事,还是仍然有意义?关于我的第二个问题,我怀疑列表分配的扁平化行为可能会以某种方式帮助支持懒惰。例如,我知道我们可以使用列表赋值来使用惰性列表中的某些值,而无需生成/计算所有值——而使用
:=
使用列表将需要计算所有 RHS 值。但我不确定是否/如何自动展平 LHS 来支持这种行为。我还想知道自动展平是否与
=
的事实有关。可以传递给元操作符——不像 :=
,如果与元操作符一起使用,则会产生“过于繁琐”的错误。但我不知道自动展平如何/是否使 =
不那么“繁琐”。[编辑:我早在 2015-05-02 就发现 IRC 引用了“(GLR 保留的)列表分配变平的决定” ,所以很明显,这个决定是有意的,而且是有充分理由的。但是,到目前为止,我还没有找到这种理由,并怀疑它可能是在面对面 session 上决定的。所以我希望有人知道。]
最后,我还想知道 LHS 是如何在概念层面扁平化的。 (我的意思不是专门在 Rakudo 实现中;我的意思是作为一种心理模型)。这是我一直在考虑绑定(bind)与列表分配的方式:
my ($a, :$b) := (4, :a(2)); # Conceptually similar to calling .Capture on the RHS
my ($c, $d, $e);
($c, ($d, $e) = (0, 1, 2); # Conceptually similar to calling flat on the LHS
除了实际拨打 .Capture
在第 1 行的 RHS 上工作,同时拨打 flat
在第 3 行的 LHS 上抛出 Cannot modify an immutable Seq
错误——我觉得这很令人困惑,因为我们扁平化 Seq
一直都是。那么,是否有更好的思维模型来思考这种自动展平行为?在此先感谢您的帮助。作为我工作的一部分,我试图更好地理解这一点 improve the related docs ,因此您可以提供的任何见解都将支持这项工作。
最佳答案
不知何故,以相反的顺序回答问题部分对我来说感觉更自然。 :-)
Second, does auto-flattening allow any behavior that would be impossible if the left hand side were non-flattening?
想要将列表的前几项(或前几项)分配为标量并将其余项放入数组是相对常见的。列表赋值下降到左侧的可迭代对象是使这项工作的原因:
my ($first, $second, @rest) = 1..5;
.say for $first, $second, @rest;'
输出为:1
2
[3 4 5]
使用尊重结构的绑定(bind),它会更像是:my ($first, $second, *@rest) := |(1..5);
First, how does this flattening behavior fit in with the rest of the language?
一般来说,结构没有意义的操作会将其扁平化。例如:
# Process arguments
my $proc = Proc::Async.new($program, @some-args, @some-others);
# Promise combinators
await Promise.anyof(@downloads, @uploads);
# File names
unlink @temps, @previous-output;
# Hash construction
my @a = x => 1, y => 2;
my @b = z => 3;
dd hash @a, @b; # {:x(1), :y(2), :z(3)}
当然,列表分配可以以一种尊重结构的方式来定义。这些事情的发生往往有多种原因,但其中一个原因是语言已经绑定(bind)了您何时想做结构化的事情,另一个原因 my ($first, @rest) = @all
只是让人们想要它沿着绑定(bind)/模糊的电动工具路径走下去有点太普遍了。
关于variable-assignment - *为什么*列表分配会变平其左侧?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69226223/