这是Perl 6哈希还是块? [英] Is that a Perl 6 Hash or Block?

查看:80
本文介绍了这是Perl 6哈希还是块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一些意外行为,可能会咬伤初学者.首先,这是故意的吗?其次,Perl 6还使用什么其他东西来猜测要创建哪个对象?它是从一开始就以为是Block还是Hash并在以后进行更改,还是最后决定?

您可以使用大括号和粗箭头构建哈希:

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

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

使用其他对"表示法也会创建一个哈希.

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

但是,没有粗箭头,我得到的是阻止:

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

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

哈希文档仅提及在括号内使用$_会创建阻止.

还有其他定义哈希的方法,但是我要问的是语法的这一点,而不是寻找我已经知道的解决方法.

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

解决方案

这仅适用于任期职位 1

仅位于词条位置的括号代码({...})受此DWIM约束. 2

在这些示例中,{...}在术语位置不是 :

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

对于此答案的其余部分,{...}仅表示在术语位置的括号代码.

摘要

如果

{...}具有显式或隐式签名,或包含顶层语句(包括变量声明),则它始终是Block.

否则,这些是Hash唯一的支撑块形式:

  • {}

  • {...},其中...是一个列表,其第一个元素是文字对(例如:bar)或% sigil'd变量(例如%foo ).

强制 BlockHash解释

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

  • 要写空的Block,请写{;}.

  • 要强制{...}构造Hash而不是Block,请改写%(...),或遵循下面解释的规则.

  • 要写空的Hash,请写{}.

显式签名表示它是Block

某些括号代码具有 explicit 签名,即它具有以下明确的参数,例如$foo.无论括号内是什么,它总是构造一个Block:

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

隐式签名也表示它是Block

一些支撑代码具有隐式签名:

  • {...}中明确使用代词"表示它是带有签名的Block,如果还没有显式签名,则为隐式签名.代词是$_@_%_.

  • 隐式通过方法调用在{...}中使用$_而不使用显式调用方,这意味着它是具有隐式签名的Block(如果尚未显式)一.换句话说,由于.foo,即使{ .foo }也具有签名((;; $_? is raw)).

  • {...}中使用显式的占位符"变量(例如,$^foo)也表示它是带有隐式签名(其中带有$foo参数的)Block.

与显式签名一样,如果括号代码具有隐式签名,则无论括号内有什么内容,它始终会构造一个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.

仍然是Block s,而不是Hash s

回想一下,要成为Hash,括号代码的内容必须是以%标记变量或 literal 对开头的列表.所以这些都产生Block s:

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)

当它是Hash

不属于上述任何情况的强制代码,将其强制为Block,并且仅仅是以% sigil'd变量或一个文字对,构造一个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)

脚语

1 参见下面关于词条位置的答案.

2 DWIM 的设计令人生厌.好的DWIM设计是值得的.但是每个DWIM都带有相应的WAT 3 .好的DWIM设计的关键是确保WAT的树皮更糟比他们的叮咬 4 ;树皮有用 5 ;并且认为DWIM应该值得一试. 6

3 WAT 指开发人员的意外惊喜当他们觉得有些疯狂时.众所周知,对于大多数适用于大多数人的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 树皮"是文档中的错误消息或警告.这些通常可以改进. cf Lock.protect({})失败,但出现令人惊讶的消息.

6 社区成员对于一般的DWIM设计,特别是任何给定的DWIM设计是否值得,存在不同意见. cf 我的观点与Sam对这个问题的回答./p>

This is a bit of unexpected behavior that's likely to bite beginners. First, is this intended? Second, what other things does Perl 6 use to guess which object to create? Does it start off thinking it's Block or Hash and change later, or does it decide on the end?

You can construct a Hash with braces and the fat arrow:

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

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

Using the other Pair notation creates a Hash too.

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

But, absent the fat arrow, I get a Block instead:

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

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

The Hash docs only mention that using $_ inside the braces creates a Block.

There are other ways to define a hash, but I'm asking about this particular bit of syntax and not looking for the workarounds I already know about.

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

解决方案

This only applies in term position1

Only braced code ({...}) that is in term position is subject to this DWIM.2

In these examples the {...} is not in term position:

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

For the rest of this answer {...} only means braced code in term position.

The summary

{...} is always a Block if it has an explicit or implicit signature, or includes top level statements, including variable declarations.

Otherwise, these are the only braced block forms that are a Hash:

  • {}

  • {...} where the ... is a list whose first element is a literal pair (eg :bar) or % sigil'd variable (eg %foo).

To force Block or Hash interpretation

  • To force {...} to construct a Block instead of a Hash, write a ; at the start i.e. { ; ... }.

  • To write an empty Block, write {;}.

  • To force {...} to construct a Hash instead of a Block, write %(...) instead, or follow the rules explained below.

  • To write an empty Hash, write {}.

An explicit signature means it's a Block

Some braced code has an explicit signature, i.e. it has explicit parameters such as $foo below. It always constructs a Block no matter what's inside the braces:

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

An implicit signature also means it's a Block

Some braced code has an implicit signature:

  • Explicit use of a "pronoun" inside {...} means it's a Block with a signature, an implicit signature if it doesn't already have an explicit one. The pronouns are $_, @_, and %_.

  • Implicit use of $_ inside {...} via a method call without an explicit invocant means it's a Block with an implicit signature if it doesn't already have an explicit one. In other words, even { .foo } has a signature ((;; $_? is raw)) due to the .foo.

  • Use of an explicit "placeholder" variable (e.g. $^foo) inside {...} also means it's a Block with an implicit signature (with a $foo parameter in it).

As with an explicit signature, if braced code has an implicit signature then it always constructs a Block no matter what's inside the braces:

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

Multiple top level statements mean it's a Block

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

The second line contains multiple statements but they're producing values within individual elements of a list that's the single top level expression.

A top level declaration of an identifier mean it's a Block

A declaration is a statement, but I've included this section just in case someone doesn't realize that.

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

The first line contains a Block as a key that contains a declaration (my $bar). But that declaration belongs to the inner {my $bar} Block, not the outer {...}. So the inner Block is just a value as far as the outer {...} is concerned, and thus that outer braced code is still interpreted as a Hash.

In contrast the second line declares a variable directly within the outer {...}. So it's a Block.

Still Blocks, not Hashs

Recall that, to be a Hash, the content of braced code must be a list that begins with either a % sigil'd variable or a literal pair. So these all produce 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)

When it's a Hash

Braced code that doesn't fall into any of the foregoing situations that force it to be a Block, and which is just a list of zero or more values that start with either a % sigil'd variable or a literal pair, constructs a 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)

Footnotes

1 See comments below answer about term position.

2 DWIM design is fraught. Good DWIM design is worth it. But every DWIM comes with corresponding WATs3. The key to good DWIM design is ensuring that, in general, WATs' barks are worse than their bites4; that the barks are useful5; and that the DWIM is considered worth the barking and biting.6

3 WAT refers to a dev's incredulous surprise when something seems crazy to them. It's known that for every DWIM that works for most folk, most of the time, there are inevitably one or more related WATs that surprise some folk, some of the time, including some of the same folk who at other times benefit from the DWIM.

4 The bite of the WATs related to this DWIM varies. It's typically a bark (error message) that makes the problem obvious, but can be much more obscure:

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 A "bark" is an error message or warning in documentation. These can often be improved. cf Lock.protect({}) fails, but with surprising message.

6 Community member opinions differ on whether DWIM design in general, or any given DWIM in particular, is worth it. cf my perspective vs Sam's answer to this question.

这篇关于这是Perl 6哈希还是块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆