---- presentation_topic: Perl 6: 有的沒的 presentation_title: Perl 6 The Ultimate presentation_place: http://autrijus.org/p6tu/start.html presentation_date: March 27th, 2005 ---- 眾人為彼造新舟 A ship then new they built for him 鑄以祕銀精靈璃 Of mithril and of elven-glass 船首閃耀何需槳 With shining prow; no shaven oar 銀桅未有風帆繫 Nor sail she bore on silver mast; 無雙寶鑽作燈炬 The Silmaril as lantern light 旗幟輝煌展生焰 And banner bright with living flame 映照燃星雅碧綠 To gleam thereon by Elbereth 神祇乘梭下九天... Herself was set, who thither came... -- Pugs 源碼, src/Main.hs ---- == 第一紀元 * Perl 1.0: 1987 冬 ** @array, %hash, $scalar, `/regex/` ** sub name { ... }, ('list'), +* Perl 2.0: 1988 夏 ** foreach, sort, do "file" ** perl -w, local($var) ---- == 第一紀元 * Perl 3.0: 1989 秋 ** GPL, pack/unpack ** &sub, undef ** package, "interpolated $s @a", sockets +* Perl 4.0: 1991 春 ** "Programming Perl" ** Artistic License ** caller, qx//, 0 + @array ---- == 第二紀元 * Perl 5.0: 1994 冬 ** OO, POD, my($var), $Package::var ** use Module, (name => "value"), tie($scalar) +* Perl 5.1: 1995 春 ** sub { ... } ** `$SIG{__WARN__}`, `$SIG{__DIE__}` ---- == 第二紀元 * Perl 5.2: 1996 春 ** sub name ($$;$) { ... } ** use overload +* Perl 5.4: 1997 春 ** $code->(@args), use 5.004; ** UNIVERSAL::isa(), UNIVERSAL::can() ---- == 第三紀元 * Perl 5.5: 1998 夏 ** B::*, threads ** tie(@array) +* Perl 5.6: 2000 春 ** use utf8 ** use warnings ** open $fh ---- == 第三紀元 * Perl 5.8: 2002 秋 ** Encode, PerlIO, iThreads, Test::More +* Perl 5.10: 2005 冬? ** 引入 Perl 6 語法 ** CPANPLUS, Module::Build, lexical pragma ---- == 世紀末駱駝革命 * 2000 年夏, 5.6 剛發佈 +* 脆弱的多執行緒和萬國碼支援 +* 疊疊樂: 挖舊功能填新功能 +* p5p 內鬥, Topaz 計劃失敗 +* "南瓜王說了算" 開發模式難以延展 +* 社群渙散, 沒有新專案出現 +* Perl 5 己經到了壽命的極限 ---- == Perl 5 架構的限制 * "向下相容" 嚴重阻礙開發 +* 核心源碼與 XS 難以維護 +* 直譯器太佔記憶體, 牽一髮動全身 +* 低階運算速度不夠快 +* 難以同時取用某個模組的多個版本 ---- == Perl 5 語言的限制 * 舊版語法和新的語義難以彌合: @a %h $s $a[0] $h{'!'} $obj->method +* 造成許多不便: sub render { my $self = shift; my %opts = @_; foreach my $item (@{$self->{_attributes}}) { print "Out: @{[$item->render(@opts{qw( x y z )}]}...\n"; } } ---- == 新世紀福音駱駝 * 更快速: 編譯成 JIT 機器碼, 可在嵌入式系統內執行 +* 更相容: 直接呼叫 Perl5/C/Java/PHP/Python/Ruby 程式庫 +* 更簡潔: 大幅縮短常用的語法 +* 更強力: 內建物件導向, 函數導向, 文件導向, 邏輯導向系統 +* 更穩定: 核心簡潔有力, 不易出錯 +* 更可塑: 自定算符, 語法, 方言, 規則... ---- == 來看看 Perl 6 * http://dev.perl.org/perl6/ +* "Never do live demo!" +* Live demo: Test.pm +* Live demo: mandel.p6 vs mandel.p5 +* Live demo: hanoi, quicksort +* Live demo: tetris.pmc ---- == 三大項 * Perl 6: 語言規範 ** Synopses/Apocalypses/Exegeses +* Parrot: 執行環境 ** Parrot Design Documents ** 0.1.2 版: 2005-03-06 +* Pugs: 編譯器 ** Pugs Apocrypha ** 6.0.13 版: 2005-03-26 ---- == 三小項 * Ponie: Perl5 直譯器 +* PPD: Perl5 翻譯器 +* PGE: Rules 編譯器 ---- == 常見問題 * 現在有哪些 Perl 6 程式可以跑? +* CPAN 上的模組還能不能用? +* Perl 5 會不會停止開發維護? +* Perl 6 是否得要從頭學起? +* Perl 6 的規格什麼時候纔會底定? +* 我想幫忙, 該怎麼做? ---- == Perl 6 {image: http://wagner.elixus.org/~autrijus/perl6.png} ---- == Perl 6: 一步步造世界 以下主要在 perl6-language@perl.org 上進行: 0 廣徵 RFC, 彙集各種主意 +0 分組腦力激盪, 提出完整的規格建議 +0 Larry 將 RFC 分出章節, 逐一寫出啟示錄 +0 設計團隊寫出相應的注疏, 提供範例 +0 社群對啟示錄及注疏提出建議 +0 設計團隊根據回應, 整理出綱要 +0 實作團隊進行初步實作 +0 設計團隊根據實作結果, 更新綱要內容 +0 實作團隊進行後續實作 ...如此直到 6.0.0 誕生為止. ---- == Perl 6: 以簡馭繁 * 霍夫曼編碼: 易行即行, 難行能行 say "Hello, World!" if $x == any(1..3); sub unfinished { ... } +* 在各種極端間求取平衝 # 太多算符 ^%+ !@== ?/ **~* ^^; -_-$ # 太少算符 assign(a, add(multiply(3, 4), 5)) +* 吸收外來語, 尊重各種文化的差異 ---- == Perl 6: 水床理論 * 此消 {image: http://wagner.elixus.org/~autrijus/bed1.png} +* 彼長 {image: http://wagner.elixus.org/~autrijus/bed2.png} +* 複雜度恆為定值 ---- == Perl 6: 避免破音字 * 如果 "cat" 這個詞是 "tog"... * 凸顯視覺差異: ** eval "..." / try { ... } ** for @a { ... } / loop (;;) { ... } ** sub a { ... } / method b { ... } ---- == Perl 6: 自由 * 給程式員最大的自由 +* 要靠習俗, 不設定律 +* 保持語言的彈性 +* 隨時反應環境的需求 ** 可變式剖析器 ** 共存的方言架構 ** 多樣文件格式 ** 使用者自定的 "核心功能" +* 因應二十年以上的長程需求 ---- == Perl 6: DWIM * 隨我所欲: Do What I Mean +* 讓 Perl 更像話 ** class Dog is Animal { has $.tail } ** m:3rd:w/word/ +* 不一定要用標準英文 ** m:3st:w/word/ ** m:nth(3):w/word/ +* 甚至不一定要用英文 ** «甲 乙 丙» ¥ (1..3); ** 書 -> 每頁 { 翻(頁) } ---- == Perl 6: 文件模型 * 透過 %=POD 來存取各種內嵌資料 ** POD ** Kwid ** XML ** YAML ** Latex * 透過共通的 DOM 互相轉換 ---- == Perl 6: 變數符號 * 符號成為變數名稱的一部份 $scalar, @array, %hash @array[3] # 不再是 $array[3] %hash{'key'} # 也可以寫成 %hash +* 因此陣列和雜湊也可以當物件用了! %hash.keys @array.sort ---- == Perl 6: 點號 * 常用的小箭頭縮短成點號了 $obj.method() $a_ref.[1] # 也可以省略成 $ref[1] $h_ref. # $h_ref, $h_ref{'key'} $c_ref.() # $c_ref() +* 點號也可以用來呼叫一般的函式 say("Hello, World!"); # 這樣可以 "Hello, World!".say; # 這樣也可以 ---- == Perl 6: 方法 * 簡單好記的方法 @array.elems # 取代了 scalar(@array) $string.chars # 取代了 length($string) $string.bytes # 取代了 bytes::length($string) @array.bytes # ... 在 Perl 5 裡寫不出來 Orz &function.arity # ... 這個也做不到 XD * 比原來的寫法好記多了 ---- == Perl 6: 具名參數 * 原來的寫法依然適用 sub sum { my $sum; $sum += $_ for @_; return $sum; } +* 新增各種具名參數 sub clean ($text, $method) { ... } # 傳址 sub by_value ($text is copy) { ... } # 傳值 sub some_opt ($req, ?$opt = $req) { ... } # 選用 sub modify ($text is rw) { ... } # 可讀寫 sub typed (Int $num, Str $txt) { ... } # 具型別 ---- == Perl 6: 呼叫函式 * 不攤平 sub whole (@names, %flags) { ... } whole(@n, %f); whole(names => ['a', 'b', 'c'], flags => { x => 1 }); whole(:names, :flags{ :x }); +* 攤平 sub flat ($first, $second) {...} flat(*@array); sub flat (*@array) {...} flat($first, $second); ---- == Perl 6: 高階函式 * 利用 .assuming 進行局部調用 (currying): sub times ($x, $y) { $x * $y } $sixtimes = ×.assuming(:y(6)); $sixtimes(9); # 54 +* 自動提取參數: sub distance { sqrt( $^a ** 2 + $^b ** 2 ) } @array.sort:{ $^y <=> $^x }; ---- == Perl 6: 多重分派函式 * 依型別分派 multi sub add (Int $a, Int $b) {...} multi sub add (Num $a, Num $b) {...} multi sub add (Str $a, Str $b) {...} +* 依值分派 multi sub factorial (0) { 1 } multi sub factorial ($n) { $n * factorial($n - 1) } ---- == Perl 6: 算符 * 新算符 say =; # 讀取算符 ...; # 啦啦啦算符 +* 萬國碼算符 sub prefix:<Σ> (@x) { sum(@x) } sub postfix: ($n) { ($n < 2) ?? 1 !! $n * ($n-1)! } say( Σ 1..5! ); # 7260 (1, 2) ¥ ('a', 'b'); # (1, 'a', 2, 'b') +* 延伸既有算符 if $x > $y > $z { ... } if -r -w 'file' { ... } ---- == Perl 6: 數值與真值 * 數值語境 $number = +$string; +* 真值語境 $true = ?$complex; +* 三元算符 $x ?? $y !! $z; ---- == Perl 6: 字串 * 字串語境與接合 $string = ~$number; $line = "Blue" ~ $moon; $ice ~= "cream"; +* 字串安插 "Hello, $person"; "You can call &subs() and $obj.methods() too!"; "The attribute is %obj.keys.sort.reverse()."; "Two plus Two is just { 2 + 2 }."; +* 字串格式化 $string.as('%10s'); @array.as('%03d', "
); %hash.as('* %s: %s', "\n"); ---- == Perl 6: 邏輯算符 * 短路與長路 $var = 9 || 3; # 9 $bool = 9 ?| 3; # Bool::True $true = 9 +| 3; # 11 $str = 9 ~| 3; # ";" +* 斜體的 || 表示 defined or $arg //= 3; $fh = open("file") err die $!; ---- == Perl 6: 超維算符 * 雙向超維 (1,1,2,3,5) »+« (1,2,3,5,8); # (2,3,5,8,13) +* 單向超維 @objects ».run(); +* 自動昇維 ('a'..'c') »x« 3; # ('aaa', 'bbb', 'ccc') ---- == Perl 6: 分叉算符 * 常用簡寫 $options = '--help' | '-d' | '-e'; if all($x, $y, $z) eq $options { ... } # 在 Perl 5 裡要寫成: if (($x eq "--help" || $x eq "-d" || $x eq "-e") and ($y eq "--help" || $y eq "-d" || $y eq "-e") and ($z eq "--help" || $z eq "-d" || $z eq "-e")) { ... } +* 質數測試 sub is_prime (Int $n) { $n % all(2 .. sqrt($n)+1) } sub has_twin (Int $n) { is_prime($n & ($n + (2 | -2))) } ---- == Perl 6: 賦名算符 * 不用再學難懂的 glob 了 &alias := ⊂ $alias := $scalar; @alias := @array; $alias := @array[2]{'many'}{'keys'}; +* 強大的惰性求值 @fib := (1, 1, @fib »+« @fib[1..Inf]) # (1, 1, 2, 3, 5, 8, 13...) ---- == Perl 6: 比對算符 * 比 `=~` 更聰明 $value ~~ /blue/; $number ~~ 5..10; $string ~~ 'hello'; +* 不祗能處理純量 @array ~~ /red/; $key ~~ %hash; $item ~~ @array; ---- == Perl 6: Switch * 用 given/when 進行比對 given $string { when 'a' .. 'z' { ... } when all(/foo/, /bar/) { ... } when .is_very_long { ... } default { ... } } * given/when 和 ~~ 用的是同樣的機制 ---- == Perl 6: 迴圈 * foreach 現在一律寫成 for for @people -> $person { say "Hello, $person"; } +* for 可以一次提取多個值 for %ages.kv -> $name, $age { say "$name is now $age"; } for zip(@a,@b) -> $a, $b { say "Are you $a or $b?"; } +* C 語言的 for 改成 loop loop ($i = 1; $i < 5; $i++) { ... } loop { do_forever() } ---- == Perl 6: 例外 * 統一使用 `$!` 例外變數, 停用 `$@`, `$?`, `$^E` system("rm -rf /") err die $!; +* eval {} 現在寫成 try {} try { may_throw_exception(); CATCH { when Error::Nasty {...} } } ---- == Perl 6: 類別 * 類別宣告 class Tree { method nodes { ... } } +* 繼承 class Leaf is Tree { has $.val; method nodes { .val } } ---- == Perl 6: 屬性 * 從 `has $.val` 自動產生建構式和存取式 my $x = Leaf.new(:val); say $x.val; # "Hello" +* 指定屬性的類別 class Branch is Tree { has Tree $.left; has Tree $.right; method nodes { (nodes .left, nodes .right) } } ---- == Perl 6: 角色 * 可隨時混進 (mixin) 的實作界面 role Storable { method freeze { ... } method thaw { ... } } +* 用 does 和 but 來混進角色 class TreeFile is Tree does Storable { ... } my $var = Leaf.new(:val(3)) but Storable; my $num = 0 but true; ---- == Perl 6: 規則 * 原有的 `m//`, `s///`, `//` 語法 if $text ~~ /blue/ {...} $name ~~ s/Dan/Chip/; m:perl5/(\()?[^()]+(?(1)\))/; +* 後綴修飾符改為前綴 m:i/yes/ # 忽略大小寫 s:g/a/b/ # 整批代換 +* 自動忽略空白和註解 (如同 Perl 5 的 //x) m{ Larry # perl6 | Chip # parrot | Autrijus # pugs }; ---- == Perl 6: 新的規則用法 * qr// 改寫成 rx// $myrule = rx/[yn]/ +* 匿名和具名規則 $myrule = rule {\w\s+\w} rule myrule {\w\s+\w} +* 規則包含規則 rule name { Larry | Chip | Autrijus } rule project { perl6 | parrot | pugs } rule description :w { does this } ---- == Perl 6: 文法 * 文法/規則 =:= 物件/方法 +* 給規則一個命名空間 grammar URI { rule reserved { <[;/?:@&=+$,\[\]]> }; rule mark { <[-_.!~*'()]> }; rule unreserved { rule { <[A-Za-z0-9]+> }; rule scheme { <[a-zA-Z]><[a-zA-Z0-9.+-]>* }; rule uri { <+++["%"]> }; } +* Perl 6 本身也是一個文法! grammar Perl6 { rule statement { ... } rule identifier { ... } } ---- == Perl 6: 一以貫之 * 易學易用 +** ...以簡馭繁 +* 特色鮮明 +** ...相互一致 +* 兼採百家 +** ...自有韻味 +* 當下實用 +** ...萬世流芳 +* 讓 Perl 更像 Perl ---- == Parrot {image: http://wagner.elixus.org/~autrijus/perl6.png} ---- == Parrot: 愚人節幻夢成真 * 什麼是 Parrot? +* Perl 6 的虛擬機器 +* 也可以跑 Python, Ruby, Scheme, Forth, BASIC +* 比 Java / .Net 適合執行動態語言 +* 大學課程 +* (開發人數 etc) ---- == Parrot: 下載安裝 * 取得穩定版本 http://search.cpan.org/dist/parrot/ http://parrotcode.org/ +* 開發版本 % svk co http://svn.perl.org/parrot/cvs/trunk/ parrot % cd parrot % perl Configure.pl % make % make test % make install ---- == Parrot: 組合語言 * 高階組語 ** IMC (Intermediate Code) ** 給編譯器使用的語言 +* 低階組語 ** PASM (Parrot Assembly) ** 內部執行的語言 +* 機器碼 ** PBC (Parrot Bytecode) ** 低階組語的二進制表示法 ---- == Parrot: 暫存器 * 直接對應到 CPU 上的暫存器: ** $I0 整數 ** $N0 浮點數 ** $S0 字串 +* Parrot Magic Cookie: ** $P0 物件 ** 自動處理繼承, 方法, 創生, 消滅 ---- == Parrot: 變數 * 用暫存器當變數 $I1 = 5 $S42 = "Hello, World\n" # 數量不限 +* 具名的區域變數和函式 # 存成 hello.pmc 就可以用 parrot 跑了 .sub _main .local string hello hello = "Hello, World\n" print hello .end ---- == Parrot: 控制結構 * 簡單的迴圈: # loop ($x = 5; $x > 0; $x--) { print $x } x = 5 REDO: # 迴圈開始 unless x > 0 goto LAST print x dec x goto REDO DONE: # 迴圈結束 +* 標記還可以存到 Continuation 物件裡 .local pmc last last = new Continuation set_addr last, DONE invoke last ---- == Parrot: 函式 * 簡單的函式: # sub foo (Int $x) { my $y = $x * 5; return $y } .sub _foo .param int x .local int y y = x * 5 .return ( y ) .end +* 呼叫函式: $I1 = _foo(3) print $I1 # 顯示 15 ---- == Parrot: 進階函式 * 多值函式 .param int bar .param int bur ... .return ( baz, buz ) ... ( $I1, $I2 ) = _foo( 5, 7 ) +* 方法呼叫 ( $I1, $I2 ) = obj."_foo"( 5, 7 ) ---- == Parrot: 程式庫 * 載入程式庫 load_bytecode "/path/to/lib/Foo.pir" +* 取得其中的函式 .local pmc here find_global here, "Foo", "there" +* 呼叫函式 result = here( 1, 2 ) ---- == Parrot: 呼叫外部程式庫 * 直接取用系統上的 `.so` 或 `.dll` loadlib libsdl, 'libSDL' $I0 = typeof libsdl dlfunc sdl_function, libsdl, 'SDL_Init', 'ii' store_global 'SDL::NCI', 'Init', sdl_function dlfunc sdl_function, libsdl, 'SDL_SetVideoMode', 'piiil' store_global 'SDL::NCI', 'SetVideoMode', sdl_function +* 立刻可以呼叫 find_global $P0, "SDL::NCI", "Init" $P0 (0, 0) ---- == Parrot: 待辦事項 * 抽象語法樹 +* 編碼轉換 +* 非同步式輸出入 +* 物件例外處理 +* 多重分派函式 ---- == Pugs {image: http://wagner.elixus.org/~autrijus/perl6.png} ---- == Pugs: 下載安裝 * 6.0.13 剛剛釋出了! http://autrijus.org/dist/Perl6-Pugs-6.0.13.tar.gz http://search.cpan.org/dist/Perl6-Pugs/ http://pugscode.org/ +* 需要先裝 GHC: http://haskell.org/ghc/download.html +* 取得開發中版本 % svk co http://svn.openfoundry.org/pugs % cd pugs % perl Makefile.PL % make % make test % make install ---- == Pugs: 發展沿革 {image: http://data.gugod.org/pugs-commits-churn.png} * 2005 年 2 月 1 日開始 (今天是第 55 天) +* 我學 Haskell 和 TaPL 的習作 +* 詳見 pugscode.org 上連到的 perl.com 訪問稿 +* 超快的開發速度 ---- == Pugs: 直譯模式 * 命令列界面 % pugs -e "'Hello, world!'.say" Hello, world! % pugs examples/japh/madgolfer.p6 Just another Pugs hacker, +* 互動式界面 % pugs pugs> { $_ ?? $_ * &?BLOCK( $_ - 1 ) !! 1 }.(10) 3628800 ---- == Pugs: 編譯模式 * 三種編譯後端 % pugscc examples/hanoi.p6 % pugscc --haskell -e "'Hello, world!'.say" % pugscc --parrot examples/mandel.p6 +* 即時執行 % pugscc --runparrot examples/mandel.p6 ---- == Pugs: 開發模式 {image: http://data.gugod.org/churn.png} * 先斬後奏: JFDI! * Wiki 式開發團隊 +* 要成為 committer, 祗有兩個條件: ** 有能力也有意願幫忙 ** 可以跟其他團隊成員溝通 +* 測試先行 ** 高爾夫先行 +* 吸引了一大堆瘋子 ---- == Pugs: 文件 * Pugs 外典 +* Kwid 文件格式 +** Kwiki 語法 +** 這張簡報就是用 Kwid 寫的 +* README 和 HOWTO ---- == Pugs: 測試 * t/ 目錄: 3000+ 個單元測試 +** 如何開始寫測試 +* examples/ 目錄: 40+ 個整合測試 +** 如何開始寫範例 +* util/ 目錄: 測試報告產生器 file:///home/autrijus/work/release/pugs/util/graph.html ---- == Pugs: 內建模組 * Test.pm * File::Spec * SHA1 ---- == Pugs: 移植中模組 * 目前有 22 個模組 Algorithm-Dependency Algorithm-FloodControl Algorithm-MarkovChain Algorithm-NaiveBayes Algorithm-TokenBucket CGI-Lite Commands-Guarded Config-Tiny Email-Envelope Email-Simple File-Basename File-Spec Geo-Distance Getopt-Std Locale-KeyedText MIME-Lite Mail-Address SQL-Routine Sample-Module Tree-Simple URI URI-Find +* 即將登場: DBI::PurePerl, HTTP::Server::Simple, YAML... ---- == Pugs: 內嵌其他語言 * Inline ** Haskell ** C +* Embed ** Perl5 ** Parrot ** Ponie ---- == Pugs: 內部架構 * Main: 主程式 * Run: 執行器 * Compile: 編譯器 * AST: 語法樹 * Bind/Junction * Extern/Embed * Parser/Lexer ---- == Pugs: 6.2 版規劃 * 基本輸出入與流程控制元件 +* 可覆寫變數 (mutable variables) +* 賦值 (assignment) +* 即時編譯器 (on-the-fly compilation) +* 即將釋出 ---- == Pugs: 6.28 版規劃 * 物件導向核心 +* 類別 (classes) +* 繼承 (inheritance) +* 特質 (traits) +* 型別 (types) +* 子型別 (subtyping) +* 內觀 (introspection) ---- == Pugs: 6.283 版規劃 * 邏輯剖析核心 +* 規則 (rules) +* 文法 (grammars) +* 回溯 (backtracking) +* 可存延續 (serializable continuations) ---- == Pugs: 遙遠的彼端 * 6.2831 ** 角色組合 (role composition) ** 其它執行時期功能 +* 6.28318 ** 巨集 (macros) +* 6.283185 ** 將 Pugs 移植至 Perl 6 ** 完成自舉 (bootstrapping) ---- == Pugs: 大家一起來! * 移植模組 +* 想想範例 +* 撰寫測試 +* 翻譯文件 +* 幫忙整理 Parrot IMC +* 學 Haskell, 改進 Pugs 核心 ---- == 謝謝!