variable-assignment - *为什么*列表分配会变平其左侧?

标签 variable-assignment raku assignment-operator destructuring flatten

我知道列表分配会使左侧变平:

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/

相关文章:

r - 为什么不应该在函数中使用 "="R 运算符?

c++ - 在对象初始化中复制构造函数

C 错误 : C2040: 'customerPtr' : 'int' differs in levels of indirection from 'customer *'

C# 自动引用分配 - 使引用为空

algorithm - 需要配对算法 - 基于匈牙利语?

regex - Perl 6 语法与我认为的不匹配

raku - 当使用 nextsame 或 callame 时,奇怪的 "Can' t use unknown trait

C++ 初学者输入错误数据类型时的无限循环并帮助评估我的代码

redis - 请求输出时 Perl6 Redis 卡住了

c++ - 如何惯用地为不可变类定义赋值运算符?