:my $foo
的作用域和用途
在 regex写烤、token 或 rule 中, 定義像下面這樣的變量是可能的:
token directive {
:my $foo = "in command";
<command> <subject> <value>?
}
在中提到了一點(diǎn)有關(guān)該變量的東西, 我引用過來:
任何 grammar regex 實(shí)際上是一種
方法
, 并且你可以在這樣一個(gè)子例程中使用一個(gè)冒號(hào)跟著任何作用域聲明符來聲明一個(gè)變量, 這些聲明符包括my
,our
,state
和constant
(作為類似的聲明符, temp 和 let 也能被識(shí)別). 單個(gè)語句(直到結(jié)尾的分號(hào)或行末尾的閉括號(hào)為止) 被解析為普通的 Perl 6 代碼:
token prove-nondeterministic-parsing {
:my $threshold = rand;
'maybe' \s+ <it($threshold)>
}
有誰能解釋下這段代碼的應(yīng)用場(chǎng)景嗎崖瞭?
what scope does :my $foo;
have?
:my $foo
在它所出現(xiàn)的 rule/token/regex 中擁有詞法作用域(lexical scope)。你所得到的作用域要么很大要么很小:
grammar g {
regex r1 {
{ my $foo; ...} # `$foo` 在該 block 的結(jié)尾超出作用域驯杜。
...
{ say $foo; } # `$foo` 不在作用域中。
}
}
grammar i {
my $foo;
regex r1 { ... } # 在 `r1` 內(nèi)部, `$foo` 被識(shí)別出核畴。
...
regex r999 { ... } # 但是在 r999 中也是丑孩。
}
它的用途?
使用 :my $foo;
形式的變量聲明以在 rule/token/regex 中聲明本地作用域的變量, 如果沒有進(jìn)一步的聲明, 那么這些變量能在 rule/token/regex 中的任何地方通過所聲明的名字來引用仗岖。舉個(gè)例子, 你可以看看 Rakudo 的 Grammar.nqp 源代碼中的 token babble
中聲明的 @extra_tweaks
變量的用法檩电。
使用 :my $*foo;
形式的變量聲明來聲明動(dòng)態(tài)的詞法變量站绪。動(dòng)態(tài)變量能夠, 在沒有進(jìn)一步聲明的情況下, 在閉合詞法作用域和閉合動(dòng)態(tài)作用域中通過它們聲明的名字來引用。作為說明, 請(qǐng)查看 the declaration of @*nibbles
in Rakudo's Grammar module 和 its use in Rakudo's Actions module 。
一般的使用場(chǎng)景
在 regular expressions 中一般不使用 :…
風(fēng)格的聲明秋泳。:...;
結(jié)構(gòu)通常用在特別復(fù)雜和龐大的 grammars 中和敬。對(duì)于這些使用場(chǎng)景, 依靠 Perl 6 的正則表達(dá)式和閉包的一致性是合適的舱痘。正是這使得 rule/token/regex 級(jí)別的 :...;
變量聲明變得正當(dāng)。
Regexes 和 closures 的一致性
很多 grammars 都是上下文有關(guān)的.
Perl 6 使 regexes 和 closures 統(tǒng)一了:
say Regex.^mro; (Regex) (Method) (Routine) (Block) (Code) ...
mro 是方法解析順序, 這足以說明 regex 實(shí)際上是一種特殊類型的方法(就像方法是一種特殊類型的子例程一樣)。
Perl6: is there a phaser that runs only when you fall out of a loop?
#!/usr/bin/env perl6
use v6.c;
ROLL:
for 1..10 -> $r {
given (1..6).roll {
when 6 {
say "Roll $r: you win!";
last ROLL;
}
default {
say "Roll $r: sorry...";
}
}
LAST {
say "You either won or lost - this runs either way";
}
}
更優(yōu)雅的寫法:
constant N = 5;
for flat (1..6).roll xx * Z 1..N -> $_, $n {
print "roll $n: $_ ";
when 6 {
put "(won)";
last;
}
default {
put "(lost)";
}
LAST {
print "result: ";
when 6 { put "winner :)" }
default { put "loser :(" }
}
}
怎么從命令行傳遞一個(gè)復(fù)數(shù)給 sub MAIN?
#!/usr/bin/env perl6
use v6.c;
sub MAIN($x)
{
say "$x squared is { $x*$x }";
}
我要在命令行中傳遞一個(gè)復(fù)數(shù)給 MAIN:
% ./square i
Cannot convert string to number: base-10 number must begin with valid digits or '.' in '?i' (indicated by ?)
in sub MAIN at ./square line 7
in block <unit> at ./square line 5
Actually thrown at:
in sub MAIN at ./square line 7
in block <unit> at ./square line 5
當(dāng)我把腳本變?yōu)?
#!/usr/bin/env perl6
use v6.c;
sub MAIN(Complex $x)
{
say "$x squared is { $x*$x }";
}
它竟然徹底罷工了:
% ./square i
Usage:
square <x>
% ./square 1
Usage:
square <x>
一種方法是使用 Coercive type declaration (強(qiáng)制類型聲明), 從 Str 到 Complex:
sub MAIN(Complex(Str) $x) {
say "$x 的平方為 { $x * $x }";
}
那么:
% ./squared.pl 1
1+0i 的平方為 1+0i
% ./squared.pl 1+2i
1+2i 的平方為 -3+4i
但是:
$ ./test.pl6 2
Usage:
./test.p6 <x>
所以你真正需要的是把其它 Numeric 類型強(qiáng)轉(zhuǎn)為 Complex 類型:
#!/usr/bin/env perl6
use v6.c;
sub MAIN ( Complex(Real) $x ) {
say "$x squared is { $x*$x }";
}
我使用 Real 而非 Numeric, 因?yàn)?Complex 已經(jīng)涵蓋了其它的了螃壤。
Blessing a Hash into an object
為什么我寫的這段代碼不對(duì)呢?
class WordCount {
has %!words; # Tried with both . and !
method new($string) {
my %words;
my @sentence = split(/\s+/, $string);
for @sentence -> $word {
%words{$word}++;
}
return self.bless(:%words);
}
method sayCounts() {
my @keys = keys(%!words);
for @keys -> $key {
say $key ~ " " ~ %!words{$key};
}
}
}
sub MAIN {
my $sentence = "the boy jumped over the dog";
my $wordCount = WordCount.new($sentence);
$wordCount.sayCounts();
}
Perl6-ify:
use v6;
class WordCount {
has Int %.words is default(0);
method new($string) {
my Int %words;
for $string.split(/\s+/) -> $word {
%words{$word}++;
}
self.bless(:%words)
}
method gist {
%.words.map({.value ~ " " ~ .key}).join("\n")
}
}
my $word-count = WordCount.new('the boy jumped over the dog');
say $word-count;
散列中的每一項(xiàng)都是一個(gè) Pair:
my %w = a => 1;
%w.map({ say $_.^name }) # OUTPUT?Pair
?
所以:
%.words.map({.value ~ " " ~ .key}).join("\n")
等價(jià)于:
%.words.kv.map( -> $word, $count { "$word $count" } ).join("\n")
你還可以使用 sub-signature(子簽名)來解構(gòu) .map
提供的 Pair
:
%.words.map( -> (:key($word), :value($count)) { "$word $count" } ).join("\n")