您的问题1和此答案仅适用于括号代码({...}
)在术语位置2。
规则
如果括号代码没有签名或包含顶层语句,并且为空或仅包含列表,其第一个元素是带有%
标记的变量(例如%foo
)或一个文字对(例如:bar
),那么它是一个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)
否则它是一个
Block
。
为了强制使用Hash
或Block
解析
详细示例
如果有人认为上述相对简单的规则有误,本回答的其余部分提供了详尽的细节。
一些带大括号的代码具有 显式 签名,即它具有显式参数,例如下面的 $foo
。无论大括号内有什么内容,它总是构造一个 Block
:
say WHAT { key => $foo, 'a', 'b' }
say WHAT -> $foo { key => $foo, 'a', 'b' }
一些带有括号的代码由于括号内遇到的语法而生成了一个隐式签名:
- 在括号内使用“代词”(`$_`,`@_`或`%_`)。这将导致一个带有签名的`Block`(如果没有显式签名,则为隐式签名)。使用`@_`或`%_`代词始终是显式的;使用`$_`可以是显式的,也可以是隐含的,例如在没有左侧参数的方法操作符(如`.method`)中。换句话说,即使`{ :foo, .key, .value }`也是一个带有签名的`Block`(`(;; $_? is raw)`),因为`.key`缺少左侧参数。
- 使用“占位符”变量(例如`$^foo`)。
与显式签名一样,如果带有隐式签名的括号代码,则无论括号内有什么内容,它始终构造一个`Block`。
say WHAT { key => @_ } # (Block)
say WHAT { key => 'value', .foo, .bar } # (Block)
顶层语句意味着它是一个块
:
say WHAT { :foo; (do 'a'), (do 'b') }
say WHAT { :foo, (do 'a'), (do 'b') }
第一行中的括号代码以
:foo;
开头;
;
表示括号代码包含语句。
第二行包含多个语句,但括号代码不将它们视为顶级语句。相反,它们在一个列表的各个元素中产生值,而列表本身不是一个语句。
对于标识符的顶级声明也意味着它是一个
Block
。声明是一种语句,但我包含了这一部分,以防有人没有意识到这一点。
say WHAT { :foo, $baz, {my $bar} } # (Hash)
say WHAT { :foo, $baz, (my $bar) } # (Block)
第一行包含一个作为值的
Block
,其中包含一个声明(
my $bar
)。但是该声明属于内部的
{my $bar}
Block
,而不是外部的
{...}
。因此,就外部
{...}
来说,内部的
Block
只是一个值,因此该外部括号代码仍然被解释为一个
Hash
。
相比之下,第二行在
{...}
内部的
括号中声明了一个变量。因此,括号代码是一个
Block
。
正如开头所指出的,要成为一个Hash
,大括号代码的内容必须是以%
标记的变量或者文字对的列表。因此,以下所有内容都将产生Block
:
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 这个“Hash还是Block?”的问题是DWIM设计的一个例子。在Raku文化中,良好的DWIM设计被认为是一件好事。但是每个DWIM都伴随着相应的WATs3。良好的DWIM设计的关键是确保总体上WATs的吠声比咬人严重4;而且这些吠声是有用的5;并且考虑到DWIM的净效益远远超过了所有的吠声和咬人行为6。
2 在Raku中,术语类似于英语中的名词或名词短语。它是一个值。
以下是术语的示例:
.say given { ... }
say 42, { ... }
示例的带括号代码不是术语。
if True { ... }
class foo { ... }
put bar{ ... }
这个回答只讨论作为术语的大括号代码。关于术语的更多细节,或者更具体地说是“术语位置”(在语法中将大括号代码解释为术语的位置),请参见本回答下面的评论。
3 WAT 是指开发人员对某些事情感到惊讶和不可思议。众所周知,即使对于设计良好的DWIM(Do What I Mean)功能,对于大多数人来说,大部分时间都能正常工作,但总会有一些相关的WATs会让一些人感到惊讶,其中甚至包括那些在其他时间从DWIM中受益的人。
4 与此DWIM相关的WATs的影响程度各不相同。通常会有一个明显的错误信息(狗叫声),以便解决问题。但它也可能更加隐晦:
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“ bark ”是文档中的错误消息或警告。这些通常可以改进。参见Lock.protect({}) fails, but with surprising message。
6社区成员对于DWIM设计是否值得,或者任何特定的DWIM是否值得,意见不一。参见my perspective和Sam对这个问题的回答。
tokens
(https://github.com/rakudo/rakudo/blob/1f89b12ee871c6bd5d753acb916ec495d959dc46/src/Perl6/Grammar.nqp#L1466-L1557和https://github.com/rakudo/rakudo/blob/1f89b12ee871c6bd5d753acb916ec495d959dc46/src/Perl6/Grammar.nqp#L3000-L3177)。此外还有[`regex term:sym<reduce>](https://github.com/rakudo/rakudo/blob/1f89b12ee871c6bd5d753acb916ec495d959dc46/src/Perl6/Grammar.nqp#L3788-L3813)以及可能的[
token termish`](https://github.com/rakudo/rakudo/blob/1f89b12ee871c6bd5d753acb916ec495d959dc46/src/Perl6/Grammar.nqp#L3627-L3659)。 - raiph<term>
的位置。我看到有四个这样的调用,其中主要的两个出现在termish
标记中此处。这就是我的回答“你所说的‘在术语位置上’是什么意思?”至于“我们是否有‘位置’这样的东西?”,我认为这些是语法中的句法槽。我想这就是我能为你提供的全部信息了。希望对你有所帮助。@jjmerelo ^^ - raiph