----
presentation_topic: Perl 6: 有的沒的
presentation_title: Perl 6 The Ultimate
presentation_place: http://wagner.elixus.org/~autrijus/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'), <FILE>

+* 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<key>

+* 因此陣列和雜湊也可以當物件用了!

    %hash.keys
    @array.sort

----
== Perl 6: 點號

* 常用的小箭頭縮短成點號了

    $obj.method()
    $a_ref.[1]      # 也可以省略成 $ref[1]
    $h_ref.<key>    # $h_ref<key>, $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<a b c>, :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 = &times.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 =<README.txt>;  # 讀取算符
    ...;                # 啦啦啦算符

+* 萬國碼算符

    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('<strong>%03d</strong>', "<br />);
    %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 := &sub;
    $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<Hello>);
    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 { <name> does this <project> }

----
== Perl 6: 文法

* 文法/規則 =:= 物件/方法

+* 給規則一個命名空間

    grammar URI { 
        rule reserved   { <[;/?:@&=+$,\[\]]>               };
        rule mark       { <[-_.!~*'()]>                    };
        rule unreserved { rule { <[A-Za-z0-9]+<mark>>      };
        rule scheme     { <[a-zA-Z]><[a-zA-Z0-9.+-]>*      };
        rule uri        { <+<reserved>+<unreserved>+["%"]> };
    }

+* 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 核心

----
== 謝謝!
