Perl 6圣誕月歷 (2012)

2012


一個(gè)日歷


#!/usr/bin/env perl6

    constant @months = <January February March April May June July August September October November December>;
    constant @days = <Su Mo Tu We Th Fr Sa>;

    sub center(Str $text, Int $width) {
        my $prefix = ' ' x ($width - $text.chars) div 2;
        my $suffix = ' ' x $width - $text.chars - $prefix.chars;
        return $prefix ~ $text ~ $suffix;
    }

    sub MAIN(:$year = Date.today.year, :$month = Date.today.month) {
        my $dt = Date.new(:year($year), :month($month), :day(1) );
        my $ss = $dt.day-of-week % 7;
        my @slots = ''.fmt("%2s") xx $ss;

        my $days-in-month = $dt.days-in-month;
        for $ss ..^ $ss + $days-in-month {
            @slots[$_] = $dt.day.fmt("%2d");
            $dt++
        }

        my $weekdays = @days.fmt("%2s").join: " ";
        say center(@months[$month-1] ~ " " ~ $year, $weekdays.chars);
        say $weekdays;
        for @slots.kv -> $k, $v {
            print "$v ";
            print "\n" if ($k+1) %% 7 or $v == $days-in-month;
        }
    }

Bags and Sets


December 13, 2012
過(guò)去幾年,我寫(xiě)了很多這種代碼的變種:

my %words;
for slurp.comb(/\w+/).map(*.lc) -> $word {
    %words{$word}++;
}

(此外: slurp.comb(/\w+/).map(*.lc) 從指定的標(biāo)準(zhǔn)輸入或命令行讀取文件,遍歷數(shù)據(jù)中的單詞蛋欣,然后小寫(xiě)化該單詞。 eg : perl6 slurp.pl score.txt)
Perl6引入了兩種新的組合類(lèi)型來(lái)實(shí)現(xiàn)這種功能。 在這種情況下,半路殺出個(gè)KeyBag 代替了 hash:

my %words := KeyBag.new;
for slurp.comb(/\w+/).map(*.lc) -> $word {
    %words{$word}++;
}

這種情況下婿屹,為什么你會(huì)喜歡 KeyBag多于 散列呢,難道是前者代碼更多嗎推溃?很好昂利,如果你想要的是一個(gè)正整數(shù)值的散列的話(huà),KeyBag將更好地表達(dá)出你的意思美莫。
> %words{"the"} = "green";

未處理過(guò)的異常:不能解析數(shù)字:green
然而KeyBag有幾條錦囊妙計(jì)页眯。首先梯捕,四行代碼初始化你的 KeyBag 不是很羅嗦厢呵,但是Perl 6能讓它全部寫(xiě)在一行也不會(huì)有問(wèn)題:

my %words := KeyBag.new(slurp.comb(/\w+/).map(*.lc));

KeyBag.new 盡力把放到它里面的東西變成KeyBag的內(nèi)容。給出一個(gè)列表傀顾,列表中的每個(gè)元素都會(huì)被添加到 KeyBag 中襟铭,結(jié)果和之前的代碼塊是完全一樣的。
如果你不需要在創(chuàng)建bag后去修改它,你可以使用 Bag 來(lái)代替 KeyBag寒砖。不同之處是 Bag 是不會(huì)改變的赐劣;如果 %words 是一個(gè) Bag,則 %words{$word}++ 是非法的哩都。如果對(duì)你的程序來(lái)說(shuō)魁兼,不變沒(méi)有問(wèn)題的話(huà),那你可以讓代碼更緊湊漠嵌。

my %words := bag slurp.comb(/\w+/).map(*.lc);  # 散列 %words不會(huì)再變化

bag 是一個(gè)有用的子例程咐汞,它只是對(duì)任何你給它的東西上調(diào)用 Bag.new 方法。(我不清楚為什么沒(méi)有同樣功能的 keybag 子例程)
Bag 和 KeyBag 有幾個(gè)雕蟲(chóng)小技儒鹿。它們都有它們自己的 .roll 和 .pick 方法化撕,以根據(jù)給定的值來(lái)權(quán)衡它們的結(jié)果:

> my $bag = bag "red" => 2, "blue" => 10;
> say $bag.roll(10);
> say $bag.pick(*).join(" ");
blue blue blue blue blue blue red blue red blue
blue red blue blue red blue blue blue blue blue blue blue
This wouldn’t be too hard to emulate using a normal Array, but this version would be:
> $bag = bag "red" => 20000000000000000001, "blue" => 100000000000000000000;
> say $bag.roll(10);
> say $bag.pick(10).join(" ");
blue blue blue blue red blue red blue blue blue
blue blue blue red blue blue blue red blue blue

sub MAIN($file1, $file2) {
    my $words1 = bag slurp($file1).comb(/\w+/).map(*.lc);
    my $words2 = set slurp($file2).comb(/\w+/).map(*.lc);
    my $unique = ($words1 (-) $words2);
    for $unique.list.sort({ -$words1{$_} })[^10] -> $word {
        say "$word: { $words1{$word} }";
    }
}

傳遞兩個(gè)文件名,這使得 Bag 從第一個(gè)文件中獲取單詞约炎,讓 Set 從第二個(gè)文件中獲取單詞植阴,然后使用 集合差 操作符 (-) 來(lái)計(jì)算只在第一個(gè)文件中含有的單詞,按那些單詞出現(xiàn)的頻率排序圾浅,然后打印出前10 個(gè)單詞掠手。
這是介紹 Set 的最好時(shí)機(jī)。就像你從上面猜到的一樣狸捕,Set 跟 Bag 的作用很像惨撇。不同的地方在于,它們都是散列府寒,而 Bag 是從Any到正整數(shù)的映射魁衙,Set 是從 Any 到 Bool::True的映射。集合Set 是不可改變的株搔,所以也有一個(gè) 可變的 KeySet .
在 Set 和 Bag 之間剖淀,我們有很豐富的操作符:


操作符 Unicode “Texas” 結(jié)果類(lèi)型

屬于  ∈   (elem)  Bool
不屬于 ?   !(elem) Bool
包含  ?   (cont)  Bool
不包含 ?   !(cont) Bool

并集  ∪   (|) Set 或 Bag
交集  ∩   (&) Set 或 Bag
差集          (-) Set

子集  ?   (<=)    Bool
非子集 ?   !(<=)   Bool
真子集 ?   (<) Bool
非真子集    ?   !(<)    Bool

超級(jí)  ?   (>=)    Bool
非超級(jí) ?   !(>=)   Bool
真超級(jí) ?   (>) Bool
非真超級(jí)    ?   !(>)    Bool

bag multiplication  ?   (.) Bag
bag addition    ?   (+) Bag
set symmetric difference (^)    Set

它們中的大多數(shù)都能不言自明。返回Set 的操作符在做運(yùn)算前會(huì)將它們的參數(shù)提升為 Set纤房。返回Bag 的操作符在做運(yùn)算前會(huì)將它們的參數(shù)提升為 Bag 纵隔。返回Set 或Bag 的操作符在做運(yùn)算前會(huì)將它們的參數(shù)提升為 Bag ,如果它們中至少有一個(gè)是 Bag 或 KeyBag炮姨,否則會(huì)轉(zhuǎn)換為 Set捌刮; 在任何一種情況下,它們都返回提升后的類(lèi)型舒岸。
eg:

> my $a = bag <a a a b b c>;  # bag(a(3), b(2), c)
> my $b = bag <a b b b>;      # bag(a, b(3))

> $a (|) $b;
bag("a" => 3, "b" => 3, "c" => 1)

> $a (&) $b;
bag("a" => 1, "b" => 2)

> $a (+) $b;
bag("a" => 4, "b" => 5, "c" => 1)

> $a (.) $b;
bag("a" => 3, "b" => 6)

下面是作者放在 github上的 Demo:

A quick example of getting the 10 most common words in Hamlet which are not found in Much Ado About Nothing:

> perl6 bin/most-common-unique.pl data/Hamlet.txt data/Much_Ado_About_Nothing.txt

ham: 358
queen: 119
hamlet: 118
hor: 111
pol: 86
laer: 62
oph: 58
ros: 53
horatio: 48
clown: 47

超棒的匿名函數(shù)


Perl6 對(duì)函數(shù)有很好的支持绅作。Perl6 令人驚嘆的把函數(shù)聲明包起來(lái),讓你可以用各種方法來(lái)定義一個(gè)函數(shù)又不丟失任何特性蛾派。你可以定義參數(shù)類(lèi)型俄认、可選參數(shù)个少、命名參數(shù),甚至在子句里也可以眯杏。如果我不知道更好的理由的話(huà)夜焦,我可能都在懷疑這是不是在補(bǔ)償 Perl5 里那個(gè)相當(dāng)基本的參數(shù)處理(咳咳 ,@_岂贩,你懂的)茫经。
除開(kāi)這些,Perl6 也允許你定義沒(méi)有命名的函數(shù)萎津。

sub {say "lol, I'm so anonymous!" }

這有什么用科平?你不命名它,就沒(méi)法調(diào)用它啊姜性,對(duì)不瞪慧?錯(cuò)!
你可以保存這個(gè)函數(shù)到一個(gè)變量里部念∑茫或者從另一個(gè)函數(shù)里 return 這個(gè)函數(shù)±芰叮或者傳參給下一個(gè)函數(shù)妓湘。事實(shí)上,當(dāng)你不命名你的函數(shù)的時(shí)候乌询,你隨后要運(yùn)行什么代碼就變得非常清晰了榜贴。就像一個(gè)可執(zhí)行的" todo "列表一樣。

現(xiàn)在讓我們說(shuō)說(shuō)匿名函數(shù)可以給我們做點(diǎn)什么妹田。在 Perl6 里它看起來(lái)會(huì)是什么樣子呢唬党?
嗯,就用最著名的排序來(lái)做例子吧鬼佣。你可能想象 Perl6 有一個(gè) sort_lexicographically 函數(shù)和一個(gè) sort_numberically 函數(shù)驶拱。不過(guò)其實(shí)沒(méi)有。只有一個(gè) sort 函數(shù)晶衷。當(dāng)你需要具體用某種形式的排序時(shí)蓝纲,你就可以傳遞一個(gè)匿名函數(shù)給 sort 。

my @sorted_words   = @words.sort({ ~$_ });
my @sorted_numbers = @numbers.sort({ +$_ });

(從技術(shù)上來(lái)說(shuō)晌纫,這是塊税迷,不是函數(shù)。不過(guò)如果你不打算在里面使用 return 的話(huà)锹漱,差異不大箭养。)
當(dāng)然你可以做的比這兩個(gè)排序辦法多多了。你可以通過(guò)鞋子大小排序凌蔬,或者最大地面速度露懒,或者自燃可能性的降序等等闯冷。因?yàn)槟憧梢园讶魏芜壿嬜鳛橐粋€(gè)參數(shù)傳遞進(jìn)去砂心。面向?qū)ο蟮慕掏絺儗?duì)這種模式可非常自豪懈词,還專(zhuān)門(mén)命名為“依賴(lài)注入”。
想想看辩诞,map 坎弯、 grep 和 reduce 都很依賴(lài)這種函數(shù)傳遞。我們有時(shí)候把這種傳遞函數(shù)給函數(shù)的做法叫“高階編程”译暂,好像這是某些高手的特權(quán)似的抠忘。但其實(shí)這是一個(gè)非常有用而且可以普通使用的技能。
上面的示例都是在當(dāng)前執(zhí)行時(shí)就運(yùn)行函數(shù)了外永。其實(shí)這里沒(méi)什么限制崎脉。我們可以創(chuàng)建函數(shù),然后稍后再運(yùn)行:

sub make_surprise_for($name) {
    return sub { say "Sur-priiise, $name!" };
}

my $reveal_surprise = make_surprise_for("Finn");    #

# 目前什么都沒(méi)發(fā)生
# 等著
# 繼續(xù)等著
# 等啊等啊等啊
$reveal_surprise();        # "Sur-priiise, Finn!"

$reveal_surpirse 里的函數(shù)記住了 $name 變量值伯顶,雖然原始函數(shù)是在很早之前傳遞進(jìn)去的參數(shù)囚灼。棒極了!這個(gè)效果就叫在 $name 變量上閉合的匿名函數(shù)祭衩。不過(guò)這里可沒(méi)什么技術(shù) -- 反正很棒就是了灶体。
事實(shí)上,如果放在其他主要存儲(chǔ)機(jī)制比如數(shù)組和散列旁邊再看匿名函數(shù)本身掐暮,這感覺(jué)是很自然的事情蝎抽。所有這些都可以存儲(chǔ)在變量里,作為參數(shù)傳遞或者從函數(shù)里返回路克。一個(gè)匿名數(shù)組允許你保存序列給以后調(diào)用樟结。一個(gè)匿名散列允許你存儲(chǔ)映射給以后調(diào)用。一個(gè)匿名函數(shù)允許你存儲(chǔ)計(jì)算或者行為給以后調(diào)用精算。
本月晚些時(shí)候狭吼,我會(huì)寫(xiě)篇介紹怎樣通過(guò) Perl6 的動(dòng)態(tài)域來(lái)創(chuàng)建漂亮的 DSL-y 接口。我們可以看到匿名函數(shù)在那里是怎么發(fā)揮作用的殖妇。

第九天:最長(zhǎng)標(biāo)示匹配


Perl6 正則表達(dá)式偏好盡可能的匹配最長(zhǎng)的選擇刁笙。

say "food and drink" ~~ / foo | food /;   # food

這跟 Perl5 不一樣。Perl5 更喜歡上面例子中的第一個(gè)選擇谦趣,結(jié)果匹配的是 "foo" 疲吸。
如果你希望的話(huà),你依然可以按照優(yōu)先匹配的原則運(yùn)行前鹅,這個(gè)原則隱藏在稍長(zhǎng)選擇操作符 || 背后:

say "food and drink" ~~ / foo || food /;  # foo

...就是這樣摘悴。這就是最長(zhǎng)標(biāo)記匹配。 ? 短文完畢舰绘。
“喂蹂喻,等等葱椭!”你聽(tīng)見(jiàn)你絕望而驚訝的大叫了,滿(mǎn)足你希望讓每天的 Perl6 圣臨歷走的慢一點(diǎn)的愿望口四》踉耍“為什么說(shuō)最長(zhǎng)標(biāo)記匹配很重要?誰(shuí)會(huì)在意這個(gè)蔓彩?”
我很高興你這樣問(wèn)治笨。事實(shí)證明,最長(zhǎng)標(biāo)記匹配(簡(jiǎn)稱(chēng) LTM )在如何解析的時(shí)候和我們的直覺(jué)配合相當(dāng)默契赤嚼。如果你創(chuàng)造了一門(mén)語(yǔ)言旷赖,你希望人們可以聲明一個(gè)叫 forest_density 的變量而不用提及這個(gè)單詞和循環(huán)里用的 for 語(yǔ)法沖突,LTM 可以做到更卒。
我喜歡“奇怪的一致性”這個(gè)說(shuō)法 -- 尤其當(dāng)程序語(yǔ)言設(shè)計(jì)的共性讓大家越來(lái)越雷同的時(shí)候等孵。這里就是一種在類(lèi)和語(yǔ)法之間的一致性。 Perl6 基本上把這種一致性發(fā)揮到了極致蹂空。讓我簡(jiǎn)單的闡述下我的意思俯萌。
現(xiàn)在我們習(xí)慣于寫(xiě)一個(gè)類(lèi),總體來(lái)看腌闯,類(lèi)差不多是長(zhǎng)這個(gè)樣子的:

class {
    method
    method
    method
}

奇怪的是绳瘟,語(yǔ)法有個(gè)非常類(lèi)似的結(jié)構(gòu):

grammar {
    rule
    rule
    rule
}

(實(shí)際上關(guān)鍵詞有 regex,token 和 rule姿骏,不過(guò)當(dāng)我們把他當(dāng)作一個(gè)組來(lái)討論的時(shí)候糖声,我們暫時(shí)統(tǒng)一叫做 rules)
我們同樣習(xí)慣于派生子類(lèi)(class B is A),然后添加或者重寫(xiě)方法來(lái)產(chǎn)生一個(gè)新舊行為在一起的組合分瘦。Pelr6 提供了 multi methods 蘸泻,它允許你添加相同名字的新方法,而且不重寫(xiě)原有的嘲玫,它只嘗試匹配所有的到新方法而已悦施。這個(gè)調(diào)度是由一個(gè)(通常自動(dòng)生成的) proto method 處理的。它負(fù)責(zé)調(diào)度給所有合格的候選者去团。

這些是怎樣用語(yǔ)法和角色運(yùn)行起來(lái)的呢抡诞?額,首先它從原有的里面派生出新的語(yǔ)法土陪,和派生子類(lèi)一樣昼汗。(事實(shí)上,底層是 完全 相同的機(jī)制鬼雀。語(yǔ)法不過(guò)是有個(gè)不同元類(lèi)對(duì)象的類(lèi)罷了顷窒。)新的角色也會(huì)重寫(xiě)原有的角色,和你在方法上習(xí)慣的一樣源哩。
S05 有個(gè)漂亮的解析信件的示例鞋吉。然后派生出來(lái)解析正式信件的語(yǔ)法:

     grammar Letter {
         rule text     {    }
         rule greet { [Hi|Hey|Yo] $=(\S+?) , $$}
         rule body     { +? }   # note: backtracks forwards via +?
         rule close { Later dude, $=(.+) }
     }

     grammar FormalLetter is Letter {
         rule greet { Dear $=(\S+?) , $$}
         rule close { Yours sincerely, $=(.+) }
     }

派生出來(lái)的 FormalLetter 重寫(xiě)了 greet 和 close鸦做,但是沒(méi)重寫(xiě) body。
但是這一切在 multi 方法下也能正常運(yùn)行嗎谓着?我們是不是可以定義一種“原型角色”來(lái)允許我們?cè)谝粋€(gè)語(yǔ)法里用同樣的名字有多種角色泼诱,內(nèi)容各不相同?比如漆魔,我們可能希望用一個(gè)角色 term 來(lái)解析語(yǔ)言坷檩,不過(guò)有很多不同的 terms:字符串却音、數(shù)字……而且數(shù)字可能是十進(jìn)制改抡、二進(jìn)制、八進(jìn)制系瓢、十六進(jìn)制等……

Perl6 語(yǔ)法可以包含一個(gè)原型角色阿纤,然后你可以定義、重定義同名角色隨便多少次夷陋。顯然讓我們回到文章最開(kāi)始的 / foo | food /欠拾。所有你起了相同名字的角色會(huì)編譯成一個(gè)大的 alternation(譯者注:輪流選擇,不確定怎么翻譯更好)骗绕。

不僅如此 -- 調(diào)用其他角色的角色藐窄,有些可能是原型角色,這些也會(huì)全部扁平化到一個(gè)大的 LTM 輪流選擇里酬土。實(shí)踐中荆忍,這意味著一個(gè) term 的所有可能會(huì)一次被全部嘗試一遍,機(jī)會(huì)平等撤缴。沒(méi)哪個(gè)會(huì)因?yàn)樽约菏窍榷x的所以勝出刹枉,只有最長(zhǎng)匹配的那個(gè)選擇才勝出。

這個(gè)奇怪的一致性說(shuō)明事實(shí)上屈呕,在調(diào)用某個(gè)方式的時(shí)候微宝,最具體的方法勝出,而且這個(gè)“最具體”必須加上引號(hào)虎眨。簽名里參數(shù)描述類(lèi)型越好蟋软,方法就越具體。
在分析某個(gè)角色的時(shí)候嗽桩,同樣是最具體的角色勝出岳守,不過(guò)這里“最具體”必須成功解析才行。角色描述下一步進(jìn)入的文本越詳細(xì)涤躲,角色就越具體棺耍。
這就是奇怪的一致性。因?yàn)楸砻嫔戏椒ê徒巧雌饋?lái)就是完全不一樣的怪獸种樱。
我們真心相信我們理解了派生語(yǔ)法的原理并且得到了一門(mén)新的語(yǔ)言蒙袍。 LTM 就是最合適的因?yàn)樗试S新舊角色通過(guò)一個(gè)公平和可預(yù)測(cè)的辦法混雜在一起俊卤。角色不是因?yàn)樗麄兌x的前后而勝出,而是因?yàn)樗茏詈玫慕馕鑫谋竞Ψ_@才是挑選精英的辦法消恍。

事實(shí)上,Perl6 編譯器自己就是這樣工作的以现。它使用 Perl6 語(yǔ)法解析你的程序狠怨,這個(gè)語(yǔ)法是可以派生的……不管你在程序里什么時(shí)候聲明了一個(gè)新操作符,都會(huì)給你派生出一個(gè)新的語(yǔ)法邑遏。新操作符的解析就作為新角色加入到新語(yǔ)法里佣赖。然后把解析剩余程序的任務(wù)交給新的語(yǔ)法。你的新操作符會(huì)勝過(guò)那寫(xiě)相同但匹配更短的记盒,不過(guò)輸給相同但匹配更長(zhǎng)的憎蛤。

開(kāi)開(kāi)心心玩Rakudo和Euler項(xiàng)目


Perl6 實(shí)現(xiàn)的領(lǐng)先者 Rakudo ,目前還不完美纪吮,說(shuō)起性能也尤其讓人尷尬俩檬。然而先行者不會(huì)問(wèn)“他快么?”碾盟,而會(huì)問(wèn)“他夠快么棚辽?”,甚至是“我怎樣能幫他變得更快呢冰肴?”屈藐。
為了說(shuō)服你Rakudo已經(jīng)能做到足夠快了。我們準(zhǔn)備嘗試做一組Euler項(xiàng)目測(cè)試嚼沿。其中很多涉及強(qiáng)行的數(shù)值計(jì)算估盘,Rakudo目前還不是很擅長(zhǎng)。不過(guò)我們可沒(méi)必要就此頓足:語(yǔ)言性能降低了骡尽,程序員就要更心靈手巧了遣妥,這正是樂(lè)趣所在啊。
所有的代碼都是在Rakudo 2012.11上測(cè)試通過(guò)的攀细。
We’ll start with something simple: 先從一些簡(jiǎn)單的例子開(kāi)始:
問(wèn)題2

想想斐波那契序列里數(shù)值不超過(guò)四百萬(wàn)的元素箫踩,計(jì)算這些值的總和。
辦法超級(jí)簡(jiǎn)單:

say [+] grep * %% 2, (1, 2, *+* ...^ * > 4_000_000);

運(yùn)行時(shí)間:0.4秒

注意怎樣使用操作符才能讓代碼即緊湊又保持可讀性(當(dāng)然這點(diǎn)大家肯定意見(jiàn)不一)谭贪。我們用了:

  • 無(wú)論如何用 * 創(chuàng)建 lambda 函數(shù)
  • 用序列操作符...^來(lái)建立斐波那契序列
  • 用整除操作符%%來(lái)過(guò)濾元素
  • 用[+]做reduce操作計(jì)算和

當(dāng)然境钟,沒(méi)人強(qiáng)制你這樣瘋狂的使用操作符 -- 香草(vanilla)命令式的代碼也沒(méi)問(wèn)題:
問(wèn)題3

600851475143的最大素因數(shù)是多少?
命令式的解決方案是這樣的:

sub largest-prime-factor($n is copy) {
    for 2, 3, *+2 ... * {
        while $n %% $_ {
            $n div= $_;
            return $_ if $_ > $n;
        }
    }
}

say largest-prime-factor(600_851_475_143);

運(yùn)行時(shí)間:2.6秒

注意用的is copy俭识,因?yàn)?Perl6 的綁定參數(shù)默認(rèn)是只讀的慨削。還有用了整數(shù)除法div,而沒(méi)用數(shù)值除法的/
到目前為止都沒(méi)有什么特別的缚态,我們繼續(xù):

問(wèn)題53

n從1到100磁椒, nCr的值,不一定要求不同玫芦,有多少大于一百萬(wàn)的浆熔?

我們將使用流入操作符==>來(lái)分解算法成計(jì)算的每一步:

[1], -> @p { [0, @p Z+ @p, 0] } ... * # 生成楊輝三角
==> (*[0..100])()                     # 生成0到100的n行
==> map *.list                        # 平鋪成一個(gè)列表
==> grep * > 1_000_000                # 過(guò)濾超過(guò)1000000的數(shù)
==> elems()                           # 計(jì)算個(gè)數(shù)
==> say;                              # 輸出結(jié)果

運(yùn)行時(shí)間:5.2s

注意使用了Z操作符和+來(lái)壓縮 0,@p 和 @p,0 的兩個(gè)列表。
這個(gè)單行生成楊輝三角的寫(xiě)法是從Rosetta代碼里偷過(guò)來(lái)的桥帆。那是另一個(gè)不錯(cuò)的項(xiàng)目医增,如果你對(duì) Perl6 的片段練習(xí)很感興趣的話(huà)。

讓我們做些更巧妙的:
問(wèn)題9

存在一個(gè)畢達(dá)哥拉斯三元數(shù)組讓 a +b + c = 1000 老虫。求a叶骨、b、c的值张遭。

暴力破解可以完成 (Polettix 的解決辦法)邓萨,但是這個(gè)辦法不夠快(在我機(jī)器上花了11秒左右)地梨。讓我們用點(diǎn)代數(shù)知識(shí)把問(wèn)題更簡(jiǎn)單的解決菊卷。
先創(chuàng)建一個(gè) (a, b, c) 組成的畢達(dá)哥拉斯三元數(shù)組:
a < b < c
a2 + b2 = c2
要求 N = a + b +c 就要符合:
b = N·(N - 2a) / 2·(N - a)
c = N·(N - 2a) / 2·(N - a) + a2/(N - a)
這就自動(dòng)符合了 b < c 的條件。
而 a < b 的條件則產(chǎn)生下面這個(gè)約束:
a < (1 - 1/√2)·N
我們就得到以下代碼了:

sub triplets(\N) {
    for 1..Int((1 - sqrt(0.5)) * N) -> \a {
        my \u = N * (N - 2 * a);
        my \v = 2 * (N - a);

        # 檢查 b = u/v 是否是整數(shù)
        # 如果是宝剖,我們就找到了一個(gè)三元數(shù)組
        if u %% v {
            my \b = u div v;
            my \c = N - a - b;
            take $(a, b, c);
        }
    }
}

say [*] .list for gather triplets(1000);

運(yùn)行時(shí)間:0.5s

注意 sigilless (譯者注:實(shí)在不知道這個(gè)怎么翻譯)變量\N洁闰,\a……的聲明,$(...)是怎么用來(lái)把三元數(shù)組作為單獨(dú)元素返回的万细,用$_.list的縮寫(xiě).list來(lái)恢復(fù)其列表性扑眉。
&triplets 子例程作為生成器,并且使用 &take 切換到結(jié)果赖钞。相應(yīng)的 &gather 用來(lái)劃定生成器的(動(dòng)態(tài))作用域腰素,而且它也可以放進(jìn) &triplets,這個(gè)可能返回一個(gè)懶惰列表雪营。
我們同樣可以使用流操作符改寫(xiě)成數(shù)據(jù)流驅(qū)動(dòng)的風(fēng)格:

constant N = 1000;

1..Int((1 - sqrt(0.5)) * N)
==> map -> \a { [ a, N * (N - 2 * a), 2 * (N - a) ] }
==> grep -> [ \a, \u, \v ] { u %% v }
==> map -> [ \a, \u, \v ] {
    my \b = u div v;
    my \c = N - a - b;
    a * b * c
}
==> say;

運(yùn)行時(shí)間:0.5s

注意我們是怎樣用解壓簽名綁定 -> [...] 來(lái)解壓傳遞過(guò)來(lái)的數(shù)組的弓千。
使用這種特殊的風(fēng)格沒(méi)有什么實(shí)質(zhì)的好處:事實(shí)上還很容易影響到性能,我們隨后會(huì)看到一個(gè)這方面的例子献起。
寫(xiě)純函數(shù)式算法是個(gè)超級(jí)好的路子洋访。不過(guò)原則上這就意味著讓那些足夠先進(jìn)的優(yōu)化器亂來(lái)(想想自動(dòng)向量化和線(xiàn)程)。不過(guò)Rakudo還沒(méi)到這個(gè)復(fù)雜地步谴餐。
但是如果我們沒(méi)有聰明到可以找到這么牛叉的解決辦法姻政,該怎么辦呢?

問(wèn)題47

求第一個(gè)連續(xù)四個(gè)整數(shù)岂嗓,他們有四個(gè)不同的素因數(shù)汁展。
除了暴力破解,我沒(méi)找到任何更好的辦法:

constant $N = 4;

my $i = 0;
for 2..* {
    $i = factors($_) == $N ?? $i + 1 !! 0;
    if $i == $N {
        say $_ - $N + 1;
        last;
    }
}

這里,&fators 返回素因數(shù)的個(gè)數(shù)食绿,原始的實(shí)現(xiàn)差不多是這樣的:

sub factors($n is copy) {
    my $i = 0;
    for 2, 3, *+2 ...^ * > $n {
        if $n %% $_ {
            ++$i;
            repeat while $n %% $_ {
                $n div= $_
            }
        }
    }
    return $i;
}

運(yùn)行時(shí)間:unknown (33s for N=3)

注意 repeat while ...{...} 的用法, 這是do {...} while(...);的新寫(xiě)法妹萨。
我們可以加上點(diǎn)緩存來(lái)加速程序:

BEGIN my %cache = 1 => 0;

multi factors($n where %cache) { %cache{$n} }
multi factors($n) {
    for 2, 3, *+2 ...^ * > sqrt($n) {
        if $n %% $_ {
            my $r = $n;
            $r div= $_ while $r %% $_;
            return %cache{$n} = 1 + factors($r);
        }
    }
    return %cache{$n} = 1;
}

運(yùn)行時(shí)間:unknown (3.5s for N=3)

注意用 BEGIN 來(lái)初始化緩存,不管出現(xiàn)在源代碼里哪個(gè)位置炫欺。還有用 multi 來(lái)啟用對(duì) &factors 的多樣調(diào)度乎完。where 子句可以根據(jù)參數(shù)的值進(jìn)行動(dòng)態(tài)調(diào)度。
哪怕有緩存品洛,我們依然無(wú)法在一個(gè)合理的時(shí)間內(nèi)回答上來(lái)原來(lái)的問(wèn)題∈饕蹋現(xiàn)在我們?cè)趺崔k?只能用點(diǎn)騙子手段了Zavolaj – Rakudo版本的NativeCall – 來(lái)在C語(yǔ)言里實(shí)現(xiàn)因式分解.
事實(shí)證明這還不夠好桥状,所以我們繼續(xù)重構(gòu)剩下的代碼帽揪,添加一些原型聲明:

use NativeCall;

sub factors(int $n) returns int is native('./prob047-gerdr') { * }

my int $N = 4;

my int $n = 2;
my int $i = 0;

while $i != $N {
    $i = factors($n) == $N ?? $i + 1 !! 0;
    $n = $n + 1;
}

say $n - $N;

運(yùn)行時(shí)間:1m2s (0.8s for N=3)

相比之下,完全使用C語(yǔ)言實(shí)現(xiàn)這個(gè)算法辅斟,運(yùn)行時(shí)間在0.1秒之內(nèi)转晰。所以目前Rakudo還沒(méi)法贏得任何一種速度測(cè)試。
重復(fù)一下士飒,用三種辦法做一件事:
問(wèn)題29

在 2 ≤ a ≤ 100 和 2 ≤ b ≤ 100 的情況下由ab生成的序列里有多少不一樣的元素查邢?
下面是一個(gè)很漂亮但很慢的解決辦法,可以用來(lái)驗(yàn)證其他辦法是否正確:

say +(2..100 X=> 2..100).classify({ .key ** .value });

運(yùn)行時(shí)間:11s

注意使用 X=> 來(lái)構(gòu)造笛卡爾乘積酵幕。用對(duì)構(gòu)造器 => 防止序列被壓扁而已扰藕。
因?yàn)镽akudo支持大整數(shù)語(yǔ)義,所以在計(jì)算像100100這種大數(shù)的時(shí)候沒(méi)有精密度上的損失芳撒。
不過(guò)我們并不真的在意冪的值邓深,不過(guò)用基數(shù)和指數(shù)來(lái)唯一標(biāo)示冪。我們需要注意基數(shù)可能自己本身就是前面某次的冪值:

constant A = 100;
constant B = 100;

my (%powers, %count);

# 找出那些是之前基數(shù)的冪的基數(shù)
# 分別存儲(chǔ)基數(shù)和指數(shù)
for 2..Int(sqrt A) -> \a {
    next if a ~~ %powers;
    %powers{a, a**2, a**3 ...^ * > A} = a X=> 1..*;
}

# 計(jì)算重復(fù)的個(gè)數(shù)
for %powers.values -> \p {
    for 2..B -> \e {
        # 上升到 \e 的冪
        # 根據(jù)之前的基數(shù)和對(duì)應(yīng)指數(shù)分類(lèi)
        ++%count{p.key => p.value * e}
    }
}

# 添加 +%count 作為一個(gè)需要保存的副本
say (A - 1) * (B - 1) + %count - [+] %count.values;

運(yùn)行時(shí)間:0.9s

注意用序列操作符 ...^ 推斷集合序列笔刹,只要提供至少三個(gè)元素芥备,列表賦值 %powers{...} = ... 就會(huì)無(wú)休止的進(jìn)行下去。
我們?cè)俅斡脭?shù)據(jù)驅(qū)動(dòng)的函數(shù)式的風(fēng)格重寫(xiě)一遍:

sub cross(@a, @b) { @a X @b }
sub dups(@a) { @a - @a.uniq }

constant A = 100;
constant B = 100;

2..Int(sqrt A)
==> map -> \a { (a, a**2, a**3 ...^ * > A) Z=> (a X 1..*).tree }
==> reverse()
==> hash()
==> values()
==> cross(2..B)
==> map -> \n, [\r, \e] { (r) => e * n }
==> dups()
==> ((A - 1) * (B - 1) - *)()
==> say();

運(yùn)行時(shí)間:1.5s

注意我們?cè)趺从?&tree 來(lái)防止壓扁的舌菜。我們可以像之前那樣用 X=> 替代 X 萌壳,不過(guò)這會(huì)讓通過(guò) -> \n, [\r, \e] 解構(gòu)變得很復(fù)雜。
和預(yù)想的一樣酷师,這個(gè)寫(xiě)法沒(méi)像命令式的那樣執(zhí)行出來(lái)讶凉。怎么才能正常運(yùn)行呢?這算是我留給讀者的作業(yè)吧山孔。
最后

解析 IPv4 地址


Perl6 的正則現(xiàn)在是一種子語(yǔ)言了懂讯,很多語(yǔ)法沒(méi)有變:
/\d+/
捕獲數(shù)字:
/(\d+)/
現(xiàn)在 $0 存儲(chǔ)著匹配到的數(shù)字,而不是 Perl 5 中的 $1. 所有的特殊變量 $0,$1,$2 在 Perl6 里就是 $/[0], $/[1], $/[2]. 在Perl 5 中,$0 是腳本或程序的文件名,但是這在 Perl6 中變成了 $*EXECUTABLE_NAME .

Should you be interested in getting all of the captured groups of a regex match, you can use @(), which is syntactic sugar for @($/).
The object in the $/ variable holds lots of useful information about the last match. For example, $/.from will give you the starting string position of the match.
But $0 will get us far enough for this post. We use it to extract individual features from a string.

修飾符現(xiàn)在放在前面了:

$_ = '1 23 456 78.9';
say .Str for m:g/(\d+)/; # 1 23 456 78 9

匹配所有看起來(lái)像這樣的東西很有用,以至于它有一個(gè)專(zhuān)門(mén)的 .comb 方法:

$str.comb(/\d+/);

如果你對(duì) .split很熟悉军熏,你可以想到 .comb 就是它的表哥瘫里,它匹配 .split丟棄的東西 实蔽。
Perl 5 中匹配 IPv4地址的正則如下:

/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/

這在 Perl6中是無(wú)效的。首先谨读,{} 塊在 Perl 6 的 正則中是真正的代碼塊局装;它們包含 Perl6 代碼。第二劳殖,在 Perl 6 中請(qǐng)使用 ** N..M (或 ** N..*) 代替 {N,M}

在 Perl 6 中匹配1到3位數(shù)字的正則如下:

/\d ** 1..3/

匹配 Ipv4地址:

/(\d**1..3) \. (\d**1..3) \. (\d**1..3) \. (\d**1..3)/

那仍有點(diǎn)笨拙铐尚。在Perl6的正則中,你可以使用重復(fù)操作符 % 哆姻,下面是重復(fù) (\d ** 1..3) 這個(gè)正則 4次宣增,并使用 . 點(diǎn)號(hào) 作為分隔符。

/ (\d ** 1..3) ** 4 % '.' /

% 操作符是一個(gè)量詞修飾符矛缨,所以它只跟在一個(gè)像 * 或 + 或 ** 的量詞后面爹脾。 上面的正則意思是 匹配 4 組數(shù)字,在每組數(shù)字間插入一個(gè)直接量 點(diǎn)號(hào) .
你也可能注意到 \. 變成了 '.' ,它們是一樣的箕昭。

$_ = "Go 127.0.0.1, I said! He went to 173.194.32.32.";

say .Str for m:g/ (\d ** 1..3) ** 4 % '.' /;
# output: 127.0.0.1 173.194.32.32

或者我們可以使用 .comb:

$_ = "Go 127.0.0.1, I said! He went to 173.194.32.32.";
my @ip4addrs = .comb(/ (\d ** 1..3) ** 4 % '.' /);   # 127.0.0.1 173.194.32.32

如果我們對(duì)單獨(dú)的數(shù)字感興趣:

$_ = "Go 127.0.0.1, I said! He went to 173.194.32.32.";
say .list>>.Str.perl for m:g/ (\d ** 1..3) ** 4 % '.' /;
# output: ("127", "0", "0", "1") ("173", "194", "32", "32")

引號(hào)


在很多地方灵妨,Perl6 都提供給你更合理的默認(rèn)設(shè)置以便在大多數(shù)情況下讓你的工作變得更簡(jiǎn)單有趣。引號(hào)也不例外盟广。
基礎(chǔ)

最常見(jiàn)的兩種引號(hào)就是單引號(hào)和雙引號(hào)闷串。單引號(hào)最簡(jiǎn)單:讓你引起一個(gè)字符串。唯一的“魔法”就是你可以用反斜杠轉(zhuǎn)義一個(gè)單引號(hào)筋量。而因?yàn)榉葱备艿倪@個(gè)作用,你可以用 \\ 來(lái)表示反斜杠本身了碉熄。不過(guò)其實(shí)這個(gè)做法也是沒(méi)必要的桨武,反斜杠自己可以直接傳遞。下面是一組例子:

> say 'Everybody loves Magical Trevor’;
Everybody loves Magical Trevor
> say 'Oh wow, it\'s backslashed!’;
Oh wow, it's backslashed!
> say 'You can include a \\ like this’;
You can include a \ like this
> say 'Nothing like \n is available’;
Nothing like \n is available
> say 'And a \ on its own is no problem’;
And a \ on its own is no problem

雙引號(hào)锈津,額呀酸,從字面上看就知道了,兩倍自然更強(qiáng)大了琼梆。:-) 它支持反斜杠轉(zhuǎn)義性誉,但更重要的是他支持內(nèi)插。也就是說(shuō)變量閉包可以放進(jìn)雙引號(hào)里茎杂。大大的幫你節(jié)約使用連接操作符或者字符串格式定義等等的時(shí)間错览。下面是幾個(gè)簡(jiǎn)單的例子:

> say "Ooh look!\nLine breaks!"
Ooh look!
Line breaks!
> my $who = 'Ninochka'; say "Hello, dear $who"
Hello, dear Ninochka
> say "Hello, { prompt 'Enter your name: ' }!"
Enter your name: _Jonathan_
Hello, Jonathan!

(that is, an array or hash subscript, parentheses to make an invocation, or a method call) 上面第二個(gè)例子展示了標(biāo)量?jī)?nèi)插,第三個(gè)則展示了閉包也可以插入雙引號(hào)字符串里煌往。閉包產(chǎn)生的值會(huì)被字符串化然后插入字符串中倾哺。那除了 $ 開(kāi)頭的呢? 規(guī)則是這樣的:所有的都可以插入,但前提是它們被某些后置框綴(譯者注:postcircumfix)(也就是帶下標(biāo)或者擴(kuò)的數(shù)組或者哈希羞海,可以做引用或者方法調(diào)用)允許忌愚。事實(shí)上你也可以把他們都存進(jìn)標(biāo)量里。

> my @beer = <Chimay Hobgoblin Yeti>;
Chimay Hobgoblin Yeti
> say "First up, a @beer[0]"
First up, a Chimay
> say "Then @beer[1,2].join(' and ')!"
Then Hobgoblin and Yeti!
> say "Tu je &prompt('Ktore pivo chces? ')"
Ktore pivo chces? _Starobrno_
Tu je Starobrno

這里你看到了一個(gè)數(shù)組元素的內(nèi)插却邓,一個(gè)被調(diào)用了方法的數(shù)組切片的內(nèi)插和一個(gè)函數(shù)調(diào)用的內(nèi)插硕糊。后置框綴規(guī)則意味著我們?cè)僖膊粫?huì)砸掉你口年的郵箱地址了(譯者注:郵箱地址里有@號(hào))。

> say "Please spam me at blackhole@jnthn.net"
Please spam me at blackhole@jnthn.net

選擇你自己的分隔符

單/雙引號(hào)對(duì)大多數(shù)情況下都很好用腊徙,不過(guò)如果你想在字符串里使用這些引號(hào)的時(shí)候咋辦癌幕?繼續(xù)用反斜杠不是什么好主意。其實(shí)你可以自定義其他字符做為引號(hào)字符昧穿。Perl6 替你選好了勺远。q和qq引號(hào)結(jié)構(gòu)后面緊跟的字符就會(huì)被作為分隔符。如果這個(gè)字符有相對(duì)應(yīng)的關(guān)閉符时鸵,那么就自動(dòng)查找這個(gè)(比如胶逢,如果你用了一個(gè)開(kāi)啟花括號(hào){,那么字符串就會(huì)在閉合花括號(hào)}處結(jié)束饰潜。注意你還可以使用多字符開(kāi)啟符和閉合符(不過(guò)要求是相同字符重復(fù)組成的多字符))初坠。另外,q的語(yǔ)義等同于單引號(hào)彭雾,qq的語(yǔ)義等同于雙引號(hào)碟刺。

> say q{C'est la vie}
C'est la vie
> say q{{Unmatched } and { are { OK } in { here}}
Unmatched } and { are { OK } in { here
> say qq!Lottery results: {(1..49).roll(6).sort}!
Lottery results: 12 13 26 34 36 46

定界符(Heredoc)

所有的引號(hào)結(jié)構(gòu)都允許你包含多行內(nèi)容。不過(guò)薯酝,還有更好的辦法:定界文檔半沽。還是用 q 或者 qq 開(kāi)始,然后跟上 :to 副詞來(lái)定義我們期望在文本最后某行匹配的字符吴菠。讓我們通過(guò)下面這個(gè)感人的故事看看它是怎么工作的者填。

print q:to/THE END/
    Once upon a time, there was a pub. The pub had
    lots of awesome beer. One day, a Perl workshop
    was held near to the pub. The hackers drank
    the pub dry. The pub owner could finally afford
    a vacation.
    THE END

腳本的輸出如下:
Once upon a time, there was a pub. The pub had
lots of awesome beer. One day, a Perl workshop
was held near to the pub. The hackers drank
the pub dry. The pub owner could finally afford
a vacation.

注意輸出文本并沒(méi)有像源程序那樣縮進(jìn)。定界符會(huì)自動(dòng)清楚縮進(jìn)到終端的級(jí)別做葵。如果我們用 qq 占哟,我們也可以往定界符里插入東西。注意這些都是通過(guò)字符串的 ident 方法實(shí)現(xiàn)的酿矢,但是如果你的字符串里沒(méi)有內(nèi)插榨乎,我們會(huì)在編譯期的時(shí)候調(diào)用 ident 作為一種優(yōu)化手段。
你同樣可以有多個(gè)定界符瘫筐,包括調(diào)用定界符里的數(shù)據(jù)的方法也是可以的(注意下面的程序就調(diào)用了 lines 方法)蜜暑。

my ($input, @searches) = q:to/INPUT/, q:to/SEARCHES/.lines;
    Once upon a time, there was a pub. The pub had
    lots of awesome beer. One day, a Perl workshop
    was held near to the pub. The hackers drank
    the pub dry. The pub owner could finally afford
    a vacation.
    INPUT
    beer
    masak
    vacation
    whisky
    SEARCHES

for @searches -> $s {
    say $input ~~ /$s/
        ?? "Found $s"
        !! "Didn't find $s";
}

這個(gè)程序輸出是:
Found beer
Didn't find masak
Found vacation
Didn't find whisky

自定義引號(hào)結(jié)構(gòu)的引號(hào)副詞

單/雙引號(hào)的語(yǔ)義,也是 q 和 qq 的語(yǔ)義严肪,已經(jīng)可以解決絕大多數(shù)情況了史煎。不過(guò)如果你有這么種情況:你要輸出內(nèi)插閉包而不是標(biāo)量怎么辦谦屑?這時(shí)候就要用上引號(hào)副詞了。它們決定你是否開(kāi)啟引號(hào)特性篇梭。下面是例子:

> say qq:!s"It costs $10 to {<eat nom>.pick} here."
It costs $10 to eat here.

這里我們使用了 qq 語(yǔ)義氢橙,但是關(guān)閉里標(biāo)量?jī)?nèi)插,這意味著我們可以放心往里寫(xiě)價(jià)錢(qián)而不用擔(dān)心他會(huì)試圖解析成上一次正則匹配的第十一個(gè)捕獲值恬偷。注意這里使用的標(biāo)準(zhǔn)的冒號(hào)對(duì)( colonpair )語(yǔ)法悍手。如果你希望從一個(gè)最基礎(chǔ)的引號(hào)結(jié)構(gòu)開(kāi)始,然后自己手動(dòng)的一個(gè)個(gè)打開(kāi)選項(xiàng)袍患,那么你應(yīng)該使用 Q 結(jié)構(gòu)坦康。

> say Q{$*OS\n&sin(3)}
$*OS\n&sin(3)
> say Q:s{$*OS\n&sin(3)}
MSWin32\n&sin(3)
> say Q:s:b{$*OS\n&sin(3)}
MSWin32
&sin(3)
> say Q:s:b:f{$*OS\n&sin(3)}
MSWin32
0.141120008059867

這里我們用了無(wú)特性引號(hào)結(jié)構(gòu),然后打開(kāi)附加特性诡延,地一個(gè)是標(biāo)量?jī)?nèi)插滞欠,然后是反斜杠轉(zhuǎn)義,然后函數(shù)內(nèi)插肆良。注意我們同樣可以選擇自己希望的任何分隔符筛璧。
引號(hào)結(jié)構(gòu)是一門(mén)語(yǔ)言

最后,值得一提的是:當(dāng)解析器進(jìn)入引號(hào)結(jié)構(gòu)的時(shí)候惹恃,其實(shí)他是切換成解析另外一個(gè)語(yǔ)言了夭谤。當(dāng)我們用副詞構(gòu)建引號(hào)結(jié)構(gòu)的時(shí)候,他只不過(guò)是把這些額外的角色混合進(jìn)基礎(chǔ)的引號(hào)語(yǔ)言里來(lái)開(kāi)啟額外的特性巫糙。好奇的童鞋可以看這里: Rakudo 怎么做到的朗儒。而當(dāng)我們碰到閉包或者其他內(nèi)插的時(shí)候,解析器再臨時(shí)切換回主語(yǔ)言参淹。所以你可以這樣寫(xiě):

> say "Hello, { prompt "Enter your name: " }!"
Enter your name: Jonathan
Hello, Jonathan!

解析器不會(huì)困惑于內(nèi)插的閉包里又帶有其他雙引號(hào)字符串的問(wèn)題醉锄。因?yàn)槲覀兘馕鲋髡Z(yǔ)言,然后切換到引號(hào)語(yǔ)言承二,然后返回主語(yǔ)言榆鼠,然后重新再返回引號(hào)語(yǔ)言來(lái)解析這個(gè)程序里的字符串里的閉包里的字符串。這就是 Perl6 解析器送給我們的圣誕節(jié)禮物亥鸠,俄羅斯套娃娃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末识啦,一起剝皮案震驚了整個(gè)濱河市负蚊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌颓哮,老刑警劉巖家妆,帶你破解...
    沈念sama閱讀 212,294評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異冕茅,居然都是意外死亡伤极,警方通過(guò)查閱死者的電腦和手機(jī)蛹找,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)哨坪,“玉大人庸疾,你說(shuō)我怎么就攤上這事〉北啵” “怎么了届慈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,790評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)忿偷。 經(jīng)常有香客問(wèn)我金顿,道長(zhǎng),這世上最難降的妖魔是什么鲤桥? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,595評(píng)論 1 284
  • 正文 為了忘掉前任揍拆,我火速辦了婚禮,結(jié)果婚禮上茶凳,老公的妹妹穿的比我還像新娘嫂拴。我一直安慰自己,他們只是感情好慧妄,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,718評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布顷牌。 她就那樣靜靜地躺著,像睡著了一般塞淹。 火紅的嫁衣襯著肌膚如雪窟蓝。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,906評(píng)論 1 290
  • 那天饱普,我揣著相機(jī)與錄音运挫,去河邊找鬼。 笑死套耕,一個(gè)胖子當(dāng)著我的面吹牛谁帕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播冯袍,決...
    沈念sama閱讀 39,053評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼匈挖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了康愤?” 一聲冷哼從身側(cè)響起儡循,我...
    開(kāi)封第一講書(shū)人閱讀 37,797評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎征冷,沒(méi)想到半個(gè)月后择膝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,250評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡检激,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,570評(píng)論 2 327
  • 正文 我和宋清朗相戀三年肴捉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腹侣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,711評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡齿穗,死狀恐怖傲隶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缤灵,我是刑警寧澤伦籍,帶...
    沈念sama閱讀 34,388評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站腮出,受9級(jí)特大地震影響帖鸦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胚嘲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,018評(píng)論 3 316
  • 文/蒙蒙 一作儿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧馋劈,春花似錦攻锰、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,796評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至械姻,卻和暖如春妒蛇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背楷拳。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工绣夺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人欢揖。 一個(gè)月前我還...
    沈念sama閱讀 46,461評(píng)論 2 360
  • 正文 我出身青樓陶耍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親她混。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烈钞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,595評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • 第5章 引用類(lèi)型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類(lèi)型 使用基本類(lèi)型...
    大學(xué)一百閱讀 3,219評(píng)論 0 4
  • 2010 第二天:用main函數(shù)控制命令行交互 2010 年 Perl6 圣誕月歷(二)用 main 函數(shù)控制命令...
    焉知非魚(yú)閱讀 467評(píng)論 0 0
  • 標(biāo)題: Rakudo and NQP Internals子標(biāo)題: The guts tormented imple...
    焉知非魚(yú)閱讀 1,360評(píng)論 1 3
  • 黛青色做底色,上有桐花刺繡坤按,雖不是上等材料布藝棵磷,但正是這種樸素,讓人宜于歡喜接受晋涣。江北的烈日,不適合過(guò)于鮮艷的色彩...
    酒色的石頭閱讀 287評(píng)論 2 1
  • 又是一年沉桌。時(shí)間已把記憶消磨的只剩下棱角谢鹊,若不是還有照片為證據(jù)算吩,那些,或許佃扼,會(huì)當(dāng)做前世了吧偎巢? 日子就在這樣忽慢忽快的...
    那年凌汛閱讀 92評(píng)論 0 1