如何将超算子与不是真正标量的标量一起使用?

Mar*_*eed 9 rakudo raku

我想对集合进行散列。好吧,SetHashes,因为它们需要是可变的。

事实上,我想用同一个 SetHash 的多个相同副本来初始化我的 Hash。

我有一个包含新哈希键的数组: @keys

我已经在标量变量中初始化了我的 SetHash: $set

我正在寻找一种干净的方法来初始化哈希。

这有效:

my %hash = ({ $_ => $set.clone } for @keys);
Run Code Online (Sandbox Code Playgroud)

(括号是优先需要的;没有它们,赋值%hashfor循环体的一部分。我可以将其更改为非后缀 for 循环或进行其他几个小更改中的任何一个,以稍微获得相同的结果不同的方式,但这不是我在这里感兴趣的。)

相反,我有点希望我可以使用 Raku 的一个漂亮的超级操作员,也许是这样的:

my %hash = @keys »=>» $set;
Run Code Online (Sandbox Code Playgroud)

$set一个简单的字符串或数字,但一个 SetHash?

Array >>=>>> SetHash can never work reliably: order of keys in SetHash is indeterminate
Run Code Online (Sandbox Code Playgroud)

很高兴知道,但我不希望它以任何顺序超过 RHS 。这就是我使用 hyperop 的右指向版本的原因:所以它会根据需要复制 RHS 以将其与 LHS 匹配。在这种表达中,有什么办法可以说“哟,乐,把它当作一个标量。不,真的。”?

我尝试了一个显式 Scalar 包装器(这会使值更难获得,但这是一个实验):

my %map = @keys »=>» $($set,)
Run Code Online (Sandbox Code Playgroud)

这让我收到了这条消息:

Lists on either side of non-dwimmy hyperop of infix:«=>» are not of the same length while recursing
left: 1 elements, right: 4 elements
Run Code Online (Sandbox Code Playgroud)

所以它显然已经递归到左边的列表中,找到了一个键,并试图将它映射到右边有 4 个元素的集合。这就是我想要的 - 映射到集合的键。但相反,它将它映射到集合的元素,而超级操作符指向了错误的大小组合。

那么为什么它会在右侧递归呢?我认为标量容器会阻止这种情况。文档说它可以防止扁平化;这种递归如何不扁平化?有什么区别?

错误消息说我使用的 hyperoperator 的版本是“非 dwimmy”,这可以解释为什么它实际上并没有按照我的意思做,但是是否有一个更小的 dwimmy 版本让我更加明确的?我的大脑还没有完全适应 Raku 的工作方式,无法可靠地告诉 WIM。

rai*_*iph 7

我正在寻找一种干净的方法来初始化哈希。

一种惯用的选择:

my %hash = @keys X=> $set;
Run Code Online (Sandbox Code Playgroud)

请参阅元X运算符


文档说……一个Scalar容器……防止扁平化;这种递归如何不扁平化?有什么区别?

猫是动物,但动物不一定是猫。扁平化可能会递归执行,但某些递归执行的操作不会扁平化。如果看到 a ,递归展平就会停止Scalar。但超操作并不是扁平化的。我知道你来自哪里,但这不是真正的问题,或者至少不是解决方案。


我原以为超运算有两个控制递归的测试:

  • 它是超nodal操作操作(例如.elems)吗?如果是这样,只需像并行浅层一样应用它map(所以不要递归)。(当前的文档非常强烈地暗示,nodal只能有效地应用于方法,并且只能应用于List一个(或其增强),而不是任何可能被过度操作的例程。这比我预期的要严格得多,我持怀疑态度其真实性。)

  • 否则,是一个值Iterable吗?如果是,则递归到该值。一般来说, a 的值Scalar自动表现为它包含的值,这适用于这里。所以Scalar不会有帮助。


ASetHash不做这个Iterable角色。所以我认为拒绝对它进行超操作是另一回事。


我刚刚搜索了源代码,在当前的 Rakudo 源代码中产生了两个匹配项,都在 Hyper 模块中,其中一个是我们正在处理的特定对象:

    multi method infix(List:D \left, Associative:D \right) {
        die "{left.^name} $.name {right.^name} can never work reliably..."
    }
Run Code Online (Sandbox Code Playgroud)

出于某种原因,超运算明确拒绝Associative在右侧或左侧使用s,而另一侧是一个List值。


在追求“责备”(跟踪谁做了什么更改)之后,我到达了提交“Die on Associative <<op>>Iterable”,它说:

由于Associative. 这曾经死过,但有一个关于Pair.new() 找不到合适候选人的LTA 错误。


也许可以改进这种行为,以便决定因素是,首先,操作数是否Iterable起作用,然后如果起作用,并且是Associative,则它死亡,但如果不是,则将其作为单个项目接受?

对GH / rakudo / rakudo问题“不能可靠地工作”的搜索率零轮的比赛。

也许提出问题?(更新我提交了“RFC:允许使用具有关联性的超级运算符,它不执行迭代角色,而不是死于“永远无法可靠地工作”。)


现在我们需要找到一些其他技术来阻止非Iterable Associative拒绝。这里我使用了Capture文字:

my %hash = @keys »=>» \($set);
Run Code Online (Sandbox Code Playgroud)

这产生:{a => \(SetHash.new("b","a","c")), b => \(SetHash.new("b","a","c")), ...


添加自定义操作会解开 en passant:

sub infix:« my=> » ($lhs, $rhs) { $lhs => $rhs[0] }
my %hash = @keys »my=>» \($set);
Run Code Online (Sandbox Code Playgroud)

这产生了预期的结果:{a => SetHash(a b c), b => SetHash(a b c), ...


my %hash = ({ $_ => $set.clone } for @keys);
Run Code Online (Sandbox Code Playgroud)

(似乎需要括号,所以它可以告诉卷曲是一个块而不是Hash文字......)

不。 curlies 中的特定代码是 aBlock无论它是否在括号中。

更一般地说,{...}术语位置形式的 Raku 代码几乎总是 a Block.

有关何时{...}序列是 aHash以及如何强制它是一个的解释,请参阅对 Raku SO 的回答是 aHash还是 a Block.


没有括号,你写了这个:

my %hash = { block of code } for @keys
Run Code Online (Sandbox Code Playgroud)

它尝试迭代@keysmy %hash = { block of code }为每次迭代运行代码。代码失败是因为您无法将代码块分配给哈希。

({ block of code } for @keys)零件周围放置括号会完全改变代码的含义。

现在它为每次迭代运行代码块。并将每次运行的结果连接成一个结果列表,每个结果都是Pair由代码生成的$_ => $set.clone。然后,当for迭代完成时,结果对列表一次被分配给my %hash

  • 嗨@jubilatious1 鉴于“my %hash = @keys X=&gt; $set”是我的答案,我想说我毫无疑问地表明它是正确的!同样,Mark 和他们的“my %hash = ({ $_ =&gt; $set.clone } for @keys)”,他们明确表示“有效”。我想让你感到困惑的是马克最初写的是“似乎需要括号*所以[Raku]可以告诉花花是一个块*”,这是不正确的,然后马克后来编辑了他们的Q以删除那一点,我没有发现,所以没有相应地编辑我的答案。我可以从我的答案中删除这一部分,但我目前认为这似乎是一个有用的花絮。 (2认同)