【问题标题】:Is that a Perl 6 Hash or Block?那是 Perl 6 哈希还是块?
【发布时间】:2017-10-21 10:26:44
【问题描述】:

这是一种可能会咬到初学者的意外行为。首先,这是故意的吗?其次,Perl 6 还使用什么其他东西来猜测要创建哪个对象?是一开始认为是 Block 还是 Hash,然后再改变,还是最终决定?

你可以用大括号和粗箭头构造一个Hash

my $color-name-to-rgb = {
    'red' => 'FF0000',
    };

put $color-name-to-rgb.^name;  # Hash

使用另一个 Pair 符号也会创建一个 Hash

my $color-name-to-rgb = {
    :red('FF0000'),
    };

但是,没有粗箭头,我得到一个 Block 代替:

my $color-name-to-rgb = {
    'red', 'FF0000',
    };

put $color-name-to-rgb.^name;  # Block

Hash 文档只提到在大括号内使用$_ 会创建一个Block

还有其他定义哈希的方法,但我询问的是这种特殊的语法,而不是寻找我已经知道的解决方法。

$ perl6 -v
This is Rakudo version 2017.04.3 built on MoarVM version 2017.04-53-g66c6dda
implementing Perl 6.c.

【问题讨论】:

    标签: hash block raku


    【解决方案1】:

    当它是Hash

    您的问题1和这个答案仅适用于术语位置2的支撑块。

    完全遵循下面解释的规则的大括号代码构造了一个Hash

    say WHAT {                  }             # (Hash)
    say WHAT { %foo             }             # (Hash)
    say WHAT { %foo, ...        }             # (Hash)
    say WHAT { foo => 42, ...   }             # (Hash)
    say WHAT { :foo, ...        }             # (Hash)
    say WHAT { key => $foo, ... }             # (Hash)
    

    规则

    如果块是空的,或者只包含一个列表,其第一个元素是% sigil'd 变量(例如%foo)或文字对(例如:bar),它确实没有有签名或包含顶级语句,它是Hash。否则为Block

    强制BlockHash解释

    • 要强制使用{...} 术语来构造Block 而不是Hash,请在开头写一个;,即{ ; ... }

    • 要写一个空的Block 术语,写{;}

    • 要写一个空的Hash 术语,写{}

    • 要强制使用 {...} 术语来构造 Hash 而不是 Block,请遵循规则(在本答案的其余部分中进行了详细说明),或者改为编写 %(...)

    显式签名意味着它是Block

    一些大括号代码具有 显式 签名,即它具有显式参数,例如下面的 $foo。不管大括号里面是什么,它总是构造一个Block

    say WHAT         { key => $foo, 'a', 'b' } # (Hash)
    say WHAT -> $foo { key => $foo, 'a', 'b' } # (Block)
    

    隐式签名也意味着它是Block

    某些大括号代码具有 隐式 签名,该签名是由于块内的某些 显式 编码选择而生成的:

    • {...} 中使用“代词”意味着它是带有签名的Block(如果还没有显式签名,则为隐式签名)。代词是$_@_%_

    • 这包括在 {...} 内隐含使用 $_,因为 .method 调用没有左侧参数。换句话说,由于.foo 缺少左侧参数,即使{ .foo } 也有签名((;; $_? is raw))。

    • 使用“占位符”变量(例如$^foo)。

    与显式签名一样,如果大括号代码具有隐式签名,则无论大括号内是什么,它总是构造一个 Block

    say WHAT { key => $_ }                     # (Block)
    say WHAT { key => 'value', .foo, .bar }    # (Block)
    

    顶级语句意味着它是Block

    say WHAT { :foo; (do 'a'), (do 'b') }     # (Block)
    say WHAT { :foo, (do 'a'), (do 'b') }     # (Hash)
    

    第二行包含多个语句,但它们在作为单个顶级表达式的列表的各个元素中生成值。

    标识符的顶级声明意味着它是Block

    声明是一种声明,但我将这一部分包括在内,以防有人没有意识到这一点。

    say WHAT { :foo, $baz, {my $bar} }        # (Hash)
    say WHAT { :foo, $baz, (my $bar) }        # (Block)
    

    第一行包含一个 Block 作为包含声明 (my $bar) 的键。但是该声明属于内部{my $bar}Block,而不是外部{...}。因此,就外部{...} 而言,内部Block 只是一个值,因此外部大括号代码仍被解释为Hash

    相比之下,第二行直接在外部{...} 中声明了一个变量。所以它是Block

    还是Blocks,而不是Hashs

    回想一下,要成为Hash,花括号代码的内容必须是一个以% sigil 变量或literal 对开头的列表。所以这些都产生Blocks:

    my $bar = key => 'value';
    say WHAT { $bar, %baz }                   # (Block)
    say WHAT { |%baz      }                   # (Block)
    say WHAT { %@quux     }                   # (Block)
    say WHAT { 'a', 'b', key => $foo }        # (Block)
    say WHAT { Pair.new: 'key', $foo }        # (Block)
    

    脚注

    1 这个“HashBlock?” question是DWIM设计的一个例子。在 Raku 文化中,好的 DWIM 设计被认为是一件好事。但是每个 DWIM 都带有相应的 WAT3。良好的 DWIM 设计的关键是确保 WAT 的 barks are worse than their bites4;并且树皮很有用5;并且 DWIM 的净收益被认为远远超过了所有的吠叫和叮咬。6

    2 术语是 Raku 对英语中名词或名词短语的类比。这是一个值。

    作为术语的大括号块示例:

    .say given { ... }  # closure? hash?
    say 42, { ... }     # closure? hash?
    

    术语的大括号块示例:

    if True { ... }     # always a closure
    class foo { ... }   # always a package
    put bar{ ... }      # always a hash index
    

    此答案仅讨论作为术语的大括号块。有关术语的更多详细信息,或者更具体地说是“术语位置”(语法中括号块将被解释为术语的位置),请参阅此答案下方的 cmets。

    3WAT 指的是开发人员在某些事情看起来很疯狂时的难以置信的惊喜。众所周知,即使对于设计良好的 DWIM,对于每个适用于大多数人的 DWIM,在大多数情况下,不可避免地会有一个或多个相关的 WAT 让一些人感到惊讶,有时,包括一些相同的人,他们在其他时间受益于 DWIM。

    4 与此 DWIM 相关的 WAT 的作用各不相同。它通常是使问题显而易见的吠声(错误消息)。但它也可能更加晦涩:

    say { a => 42 }() ;  # No such method 'CALL-ME' for invocant of type 'Hash'   WAT? Oh.
    say { a => $_ }<a> ; # Type Block does not support associative indexing.      WAT? Oh.
    
    say { a => $_, b => 42, c => 99 } .elems  # 1                                 WAT?????
    

    5 “吠叫”是文档中的错误消息或警告。这些通常可以改进。参考Lock.protect({}) fails, but with surprising message

    6 社区成员对于一般的 DWIM 设计或任何特定的 DWIM 是否值得持有不同意见。 cf my perspective vs Sam 对这个问题的回答。

    【讨论】:

    • “在任期内”是什么意思?我们有诸如“职位”之类的东西吗?如果是这种情况,则应记录在案。
    • 术语位置表示语言语法可以接受term 的位置。正如我链接的文档所说,“Perl 6 中的大多数语法结构都可以按术语和运算符进行分类。”我认为它对应于一个值,其中包含一个表达式,不能进一步分解为一个值列表。呃,用英语来说,就像名词或名词短语可以出现的位置一样。在实现方面,我认为它对应于 Rakudo 的 Perl 6 Grammar.nqp 文件中的term 规则...
    • 我在设计文档中找到的“术语位置”的匹配项都没有定义它。我认为这是一个众所周知的术语(!)在一般解析中,特别是在 P5 文化中,所以拉里没有费心去定义它。这种追捕它的尝试让我想起了我以前研究过它...这使我进入my SO answer to “Two terms in a row” error 中的术语是什么?部分。这很蹩脚。我建议问问拉里。
    • 现在我的结论是“术语位置”归结为在 Grammar.nqp 中调用 &lt;term&gt; 的位置。我看到四个这样的调用,其中主要是出现在termish 令牌here 中的两个。这包括我回答您的问题“您所说的“术语位置”是什么意思?至于“我们有诸如“位置”之类的东西吗?”,我会说这些是语法中的句法槽。我想这就是我为你准备的一切。希望对你有所帮助。@jjmerelo ^^
    • 我现在为这个github.com/Raku/doc/issues/3774创建了一个问题,当时应该这样做......
    【解决方案2】:

    首选的 Perl6 方法是使用 %( ) 创建哈希。

    my $color-name-to-rgb = %(
        'red', 'FF0000',
        );
    

    我永远不会建议人们使用大括号来创建哈希值。如果他们想进行哈希,那么%( ) 是正确的做法。

    如果您来自 Perl 5 世​​界,最好养成在创建哈希时使用 %( ) 而不是 { } 的习惯。

    【讨论】:

    • 我似乎记得用 '{ }' 创建散列通常会引发错误并告诉您使用 '%( )'。在我看来,这种行为应该会回归。
    • 文档需要进行重大更新以反映这一点。当{} 不起作用时,%() 被提及作为替代。如果不是文档,首选方式的来源在哪里?
    • 我完全同意布赖恩的评价。我在这里打开了一个文档问题github.com/perl6/doc/issues/1380 我们曾经有过弃用警告,这些警告会在程序完成后显示,也许这是我们在使用{ } 创建哈希时可能想要为 6.d 添加的内容。
    • 现在包括in the style guide as a recommendation。感谢您的问题。
    猜你喜欢
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 2016-10-04
    • 2013-01-10
    • 2012-01-23
    相关资源
    最近更新 更多