2016-10-20 號更新。
General
Rakudo 和 Perl 6 的區別是什么?
Rakudo 是 Perl 6 的一個實現。目前它是完成度最好的但是過去也有其它的實現, 將來也可能會有其它實現。Perl 6 是語言的定義。很多場合
這兩個名字可以寬松地使用并互相替換。
會有 Perl 6 版本 6.0.0 嗎?
第一個穩定語言版本的版本稱為 v6.c,而不是 6.0.0。 不同的命名方案使得不太可能發布具有精確版本 6.0.0 的語言。
您可以使用下面的代碼檢查您的 Rakudo 編譯器是當前至少是什么版本(注意這可能不是真正的供應商二進制文件):
perl6 -e 'say q[too old] if $*PERL.version before Version.new(q[6.c])'
它首先由 Rakudo Perl 6 編譯器版本的 2015.12 實現,并且可能通過使用 'use 6.c' 指令在可預見的未來支持后續版本。 下一個語言版本(無發布日期)為 v6.d.
作為一個 Perl 6 初學者我應該安裝什么?
如果你是一個 Linux 或 Mac 用戶, 你可能需要下載 Rakudo Star 并通過編譯 MoarVM 版本安裝(一個簡單的處理)
如果你是一個 Windows 32 或 64 位用戶, 那么 Rakudo Star 二進制版本在 rakudo 網站也能獲得。你需要 Windows Git 來使用 panda。
Linux 和 Mac 二進制版本稍后也可能從供應商和第三方那兒獲取到。盡管供應商版本可能過時了。
或者有一個官方的 rakudo star Docker 鏡像, 地址為 https://hub.docker.com/_/rakudo-star/
作為一個中高級用戶我想跟進 Rakudo 開發
安裝類似于 Perl 5 的 perlbrew -- rakudobrew , 同等的 Python 還有 Ruby 工具。
從哪里能找到關于 Perl 6 的好文檔?
最令人信賴的信息能在 perl6.org 或那兒的直接鏈接。
你也可以使用 Google 搜索 Freenode #perl6 IRC 頻道。
http://www.perl6.org/documentation/ 和 http://doc.perl6.org/
什么是 Perl 6 spec?
"spec" 指的是 Perl 6的官方測試套件。它被稱作 roast 并被托管在 github 上.
它被用來測量一個 Perl 6 的實現有多徹底。
有沒有 Perl 6 的術語相關的項目?
查看 glossary
我是一個 Perl 5 程序員. Perl 5 和 Perl 6 的區別在哪兒?
在 https://docs.perl6.org/language/5to6-nutshell 下面查看 ‘5to6-nutshell’ pod 文檔和相關頁面。
模塊
Perl 6 有 CPAN 嗎? 或者 Perl 6 會使用 Perl 5 的 CPAN 嗎?
Perl 6 還沒有像 CPAN 那樣成熟的模塊倉庫. 但是 modules.perl6.org 有很多已知的 Perl 6 模塊, panda 能在 Rakudo 上安裝這些模塊.
我能在 Perl 6 中使用 Perl 5的模塊嗎?
使用 Inline::Perl5 能讓大部分 Perl 5 模塊工作, 它甚至能很好地運行 Perl 5 的 Catalyst 和 DBI。
我能在 Perl 6 中使用 C 和 C++ 嗎?
Nativecall 讓這個特別容易。
Nativecall 找不到 libfoo.so 并且我只有 libfoo.so.1.2!
這在 Debian 那樣的系統中很常見。 你需要安裝 "libfoo-dev" 來為丟失的文件設置符號鏈接。
所有的傳統 Unix 庫函數去哪兒了?
使用 Nativecall 訪問它們很容易。
POSIX 模塊也可以。
Rakudo 有核心標準庫嗎?
Rakudo 是一個包含最小電量的編譯器發布(Test 和 Nativecall等等),像 linux 內核一樣。
Rakudo Star 是一個帶有一些有用模塊的 rakudo, 并且更多的模塊可以從生態系統里安裝。
有像 B::Deparse 那樣的東西嗎?/我怎么抓住 AST?
使用 perl6 --target=ast -e 'very-short-example()'
來抓取編譯單元的抽象語法樹(AST)。
語言特性
我怎么 dump Perl 6 的數據結構(就像 Perl 5 的 Data::Dumper 和類似的)?
examples:
my $foo="bar"
dd $foo # Str $foo = "bar"
say :$foo.perl # :foo("bar")
say :$foo.gist # foo => bar
生態系統中還有模塊來做這個事情, 例如 Data::Dump 使用顏色來 Dump。
我怎么在 Perl 6 提示符(REPL)中找到歷史命令行?
從生態系統中安裝 Linenoise.
作為一種選擇, 在 UNIX 那樣的系統中可以安裝 rlwrap。這在類 Debian 系統中可以通過apt-get install rlwrap
安裝。
為什么 Rakudo 編譯器有時候報錯更友好?
如果在輸出中出現 SORRY!
, 則錯誤是編譯時錯誤, 否則是運行時錯誤。
Examples:
say 1/0 # Attempt to divide 1 by zero using div
sub foo ( Int $a, Int $b ) {...}
foo(1) # ===SORRY!=== Error while compiling ...
什么是 (Any)?
Any 是一個用于新類的默認超類(superclass)的頂層類。
它經常在這樣的上下文出現:變量被定義但沒有被賦值, 這里它類似于其它語言中的 undef 或 null 值。
examples:
my $foo;
say $foo; # (Any) 注意圓括號表明的類型對象
say $foo.^name # Any
(Any) 不應該被用于檢查 definedness。 在 Perl 6 中, definedness 可能是一個對象的屬性。 通常實例是被定義的, 而類型對象是未定義的。
say 1.defined # True
say (Any).defined # False
so 是什么?
so
是一個松散優先級的操作符, 它強制上下文為 Bool.
so
擁有和 ?
前綴操作符同樣的語義, 就像 and
是 &&
的低優先級版本一樣.
用法示例:
say so 1|2 == 2; # Bool::True
在這個例子中, 比較的結果(結果是 Junction)在打印之前被轉換為 Bool 值了.
簽名中的那些 :D 和 :U 是什么東東?
在 Perl 6 中, 類和其它類型是對象, 并且傳遞自身類型的類型檢測。
例如如果你聲明一個變量
my Int $x = 42;
那么, 你不僅可以給它賦值整數(即, Int 類的實例), 還能給它賦值 Int 類型對象自身:
$x = Int
如果你想排除類型對象, 你可以追加一個 :D
類型微笑符, 它代表"定義"(definite):
my Int:D $x = 42;
$x = Int; # dies with:
# Type check failed in assignment to $x;
# expected Int:D but got Int
同樣地, :U
約束為未定義的值, 即類型對象。
要顯式地允許類型對象或實例, 你可以使用 :_
。
簽名中的 --> 是什么東東?
-->
是一個返回值約束, 要么是類型要么是有定義的值。
類型約束的例子:
sub divide-to-int( Int $a, Int $b --> Int ) {
return ($a / $b).narrow;
}
divide-to-int(3, 2)
# Type check failed for return value; expected Int but got Rat
有明確返回值的例子:
sub discard-random-number( --> 42 ) { rand }
say discard-random-number
# 42
在這種情況下,最終值被拋棄,因為已經指定了返回值。
Any 和 Mu 的區別是什么?
Mu
是所派生出的所有其它類型的基類型. Any
是從 Mu
派生來的, 代表著任何類型的 Perl 6 值. 主要區別是, Any
不包含 Junction
.
子例程參數的默認類型是 Any
, 以至于當你聲明 sub foo ($a)
時, 你真正表達的是 sub foo (Any $a)
. 類似地, 類的聲明被假定繼承自 Any
, 除非使用了像 is Mu
這樣的 trait 特征.
怎么從 Junction 中提取值?
如果你想從 Junction 中提取值(特征態), 那你可能正誤入歧途. 應該使用 Set 代替
Junctions 作為匹配器, 而不是使用它們做代數.
如果你還是想那樣做, 你可以濫用自動線程(autothreading):
sub eigenstates(Mu $j) {
my @states;
-> Any $s { @states.push: $s }.($j);
@states;
}
say eigenstates(1|2|3).join(', ');
# prints 1, 2, 3 or a permutation thereof
如果 Str 是不可變的, 那么 s///
是怎么工作的? 如果 Int 是不可變的, $i++
是怎么工作的?
在 Perl 6 中, 很多基本類型是不可變的, 但是保存它們的變量不是. s///
作用于變量上, 在這個變量中放入一個新創建的字符串對象. 同樣地, $i++
作用于 $i
變量上, 而不是作用在它里面的值身上.
更多詳情請查看: containers 文檔。
什么是數組引用和自動解引用? 我仍然需要 @ 符號嗎?
在 Perl 6 中, 幾乎所有的東西都是引用. 所以談論 taking references 沒有多大意義. 不像 Perl 5 那樣, Perl 6 的標量變量也能直接包含數組:
my @a = 1, 2, 3;
say @a; # "1 2 3\n"
say @a.WHAT; # (Array)
my $scalar = @a;
say $scalar; # "1 2 3\n"
say $scalar.WHAT; # (Array)
最大的區別是, 標量中的數組在列表上下文中是一個值, 然而數組會被愉快地迭代:
my @a = 1, 2, 3;
my $s = @a;
for @a { ... } # loop body executed 3 times
for $s { ... } # loop body executed only once
my @flat = flat @a, @a;
say @flat.elems; # 6
my @nested = flat $s, $s;
say @nested.elems; # 2
你可以使用 @( ... )
或通過在表達式身上調用 .list
方法來強制展平, 使用 $( ... )
或通過在表達式身上調用 .item
方法強制為 item 上下文(不展平).
為什么還要符號? 你不能沒有它們嗎?
有幾個原因:
- 它們使插值變量到字符串中變得更容易
- 它們為不同的變量和 twigils 組成了微型命名空間, 因此避免了名字沖突
- 它們允許簡單的 單數/復數 區別
- 它們像使用強制性名詞標記的自然語言一樣工作,所以我們的大腦為處理它而生
- 它們不是強制性的,因為你可以聲明無符號名字(如果你不介意含糊不清)
"類型 Str 不支持關聯索引"
你可能會把字符串插值和 HTML 搞混。
my $foo = "abc";
say "$foo<html-tag>";
Perl 6 認為 $foo
是一個散列而 <html-tag>
是一個字符串字面量的散列鍵。使用閉包來幫助你理解吧。
my $foo = "abc";
say "{$foo}<html-tag>";
Perl 6 有協程嗎? 什么是 yield ?
Perl 6 沒有 Python 那樣的 yield
語句, 但是它通過惰性列表卻能提供類似的功能. 有兩種很潮的方式來寫出能返回惰性列表的例程:
# first method, gather/take
my @values := gather while have_data() {
# do some computations
take some_data();
# do more computations
}
# second method, use .map or similar method
# on a lazy list
my @squares := (1..*).map(-> $x { $x * $x });
# or
my @squares = (1..*).map(-> \x { x2 });
為什么我需要反斜線(unspace)在多行上分割方法調用?
(請在這兒添加答案)
為什么我不能從 new 方法初始化私有屬性, 我怎么修復它?
這樣的代碼:
class A {
has $!x;
method show-x {
say $!x;
}
}
A.new(x => 5).show-x;
不會打印出 5. Private 屬性是私有的, 這意味著私有屬性在外面是不可見的. 如果默認的構造器能夠初始化私有屬性, 那么這些私有屬性就會泄露到公共 API 中.
如果你仍舊想讓它工作, 你可以添加一個 submethod BUILD
來初始化它們:
class B {
has $!x;
submethod BUILD(:$!x) { }
method show-x {
say $!x;
}
}
A.new(x => 5).show-x;
BUILD
由默認的構造器使用用戶傳遞給構造器的所有具名參數調用(間接地, 更多細節查看Object Construction)。 :$!x
是名為 x
的具名參數, 當使用名為 x
的具名參數來調用時, 它的值被綁定到屬性 $!x
上.
但不要這樣做。如果名字是 public 的,使用 $.x
以那樣的方式聲明沒有什么不好,因為默認情況下外部視圖是只讀的(readonly),你仍然可以使用 $!x
從內部訪問它。
say, put 和 print 怎么不同, 為什么不同?
最明顯的區別是, say
和 put
在輸出后面添加了一個換行符, 而 print
沒有.
但是還有另外一個區別: print
和 put
通過對每一個傳遞來的 item 調用 Str
方法來把它的參數轉換為字符串, 相反, say
使用 gist
方法. 前者是為計算機設計的, 后者是為人類.
或者它倆被解析的方式不同, $obj.Str
給出一個字符串表示, $obj.gist
是對象的一個簡短總結, 適合編程人員的快速識別, $obj.perl
打印一個 Perlish 的表示.
例如, 類型對象, 也是熟知的 “未定義值”, 字符串化為一個空的字符串和警告, 而 gist
方法返回由一對圓括號包裹的類型的名字.(用于表明除了類型之外什么也沒有).
my Date $x; # $x now contains the Date type object
print $x; # empty string plus warning
say $x; # (Date)\n
所以, say
優化的用于調試和向人們展示, print
和 put
更適合于產生用于其它程序的輸出.
put
因此是 print
和 say
之間的一種混合; 像 print
, 它的輸出適合于其它程序, 也像 say
, 它在輸出的末尾添加了換行符。
token 和 rule 之間的區別是什么?
regex
, token
和 rule
這三個都引入了正則表達式, 但是語義略微有一點不同.
token
隱含了 :ratchet
或 :r
修飾符, 這防止了 rule 的回溯.
rule
隱含了 :ratchet
和 :sigspace
(縮寫為 :s
)修飾符, 這意味著規則(rule)不會回溯, 并且它把 regex 的文本中的空白當作 <.ws>
調用(例如匹配空白, 除了在兩個單詞字符之間之外, 它是可選的). regex 開頭的空白和備選分支中每個分支開頭的空白會被忽略.
regex
聲明一個簡單的正則表達式,沒有任何隱含的修飾符。
die 和 fail 之間的區別是什么?
die
拋出一個異常.
fail
返回一個 Failure 對象。 (如果調用者已經聲明了 use fatal;
在調用作用域中, fail
會拋出一個異常而不返回)
Failure
是一個 “未知的” 或 “懶惰的” 異常.它是一個含有異常的對象, 當這個 Failure 被用作普通的對象或者在 sink 上下文中忽略它時, 則會拋出一個異常.
Failure 從 defined
檢查中返回 False, 并且你可以使用 exception
方法提取出異常.
為什么 wantarray 或 want 不見了? 我能在不同的上下文中返回不同的東西嗎?
Perl 擁有 wantarray 函數來告訴你這是在空上下文, 標量上下文,還是在列表上下文中調用的. Perl 6 沒有與之等價的結構, 因為上下文不是向內流動的, 例如, 子例程不知道調用所在的上下文.
一個愿意是因為 Perl 6 有多重分派, 在這樣一個例子中:
multi w(Int $x) { say 'Int' }
multi w(Str $x) { say 'Str' }
w(f());
沒辦法決定子例程 f
的調用者想要一個字符串還是想要一個整數, 因為它還不知道調用者是什么. 通常這要求解決 halting 問題, 在這個問題上, 即使寫 Perl 6編譯器的人也會遇到麻煩.
在 Perl 6 中達到上下文敏感的方式是返回一個知道怎樣響應方法調用的對象.
例如, regex 匹配返回 Match 對象, 該對象知道怎樣響應列表索引, 散列索引, 并能變成匹配的字符串.
Pointer 和 OpaquePointer 的區別是聲明?
OpaquePointer
被廢棄了并且已經用 Pointer
代替了。
Perl 6 實現
哪個 Perl 6 的實現是可用的?
當前開發最好的是 Rakudo(使用多個虛擬機后端)。歷史上的實現還包括 Niecza (.NET) 和 Pugs (Haskell). 其它的列出在 Perl 6 Compilers 下面。
Rakudo 是用什么語言寫的?
NQP 是(1)NQP 代碼,(2)底層虛擬機使用的任何語言,(3)一些第三方 C 和 Java 庫,以及(4)早期運行構建過程創建的一些引導文件的混合 。
為什么我不能把所有的數值都賦值給 Num 類型的變量?
my Num $x = 42;
# dies with
# Type check failed in assignment to '$x'; expected 'Num' but got 'Int'
Num 是浮點類型, 與 integers 不兼容. 如果你想要一個允許任何數字值的類型約束, 使用 Numeric (它也允許復數), 或 Real如果你想排除復數.
元問題和宣傳
Perl 6 什么時間會準備好? 就是現在嗎?
編程語言和它們的編譯器的準備就緒不是一個二元決策. 因為它們(語言和實現)能進化, 它們平穩地發展變得更可用. 根據你對編程語言的要求, 它可能適合也可能不適合你.
請查看 功能對比矩陣 了解更詳盡的實現了的功能.
請注意, Larry Wall 已經在 FOSDEM 2015 會議上宣布, 一個產品級的 Rakudo Perl 6 將會在 2015 圣誕節發布.
為什么我要學習 Perl 6? 它有什么了不起的嗎?
Perl 6 統一了很多其它編程語言中不經常有的偉大想法. 雖然其中的幾種語言提供了其中的某些功能, 但是沒有提供全部.
不像大部分語言那樣, 它提供了:
- Perl 6 提供了過程式的, 面向對象的和函數式編程方法。
- 易于使用的一致性語法, 數據結構中的符號不變性。
- 完全基于字素的 Unicode 支持, 包括附件 #29
- 足夠清晰的正則表達式, 更易讀, 更多功能。
- Junctions 允許多個可能性的簡單檢測, 例如 $a == 1|3|42(意思是 $a 等于 1 或 3 或 42)
- 相對于全局變量, 動態作用域變量提供了詞法作用域備選
- 強調可組合性和本地作用域以阻止「超距作用」。例如, imports 總是本地作用域的。
- 易于理解的一致性作用域規則和閉包
- 強大的面向對象, 含有類和 roles(所有的東西都可以當做對象)。繼承、子類型、代碼復用。
- 內省到對象和元對象中(疊羅漢)
- 元對象協議允許元編程而不需要生成/解析代碼。
- 子例程和方法簽名,便于解包位置參數和命名參數。
- 根據元數,類型和可選的額外代碼使用不同的簽名對同一具名子例程/方法進行多重分派。
- 未知子例程/不可能的分派在編譯時給出錯誤報告。
- 可選的漸進類型檢查,無需額外的運行時成本。 還有可選類型注解。
- 基于對編譯器/運行時狀態的內省的高級錯誤報告。這意味著更有用,更精確的錯誤信息。
- Phasers(如 BEGIN/END) 允許代碼作用域 進入/退出, 首次循環/last/next 和其它更多上下文中執行。
- 高級并發模型,用于隱式以及顯式多進程處理,這超越了原始線程和鎖。 Perl 6 的并發提供了一組豐富的(可組合的)工具。
- 多核計算機越來越多地被使用,由于并行性使得 Perl 6 可以使用多核,包括隱式(例如使用>>.方法)和顯式 (start {code}) 。這很重要,因為摩爾定律正在結束。
- 提供結構化語言支持以實現異步執行代碼的編程。
- Supplies 允許在發生某些事情時執行代碼(如定時器,信號或文件系統事件)。
- react/whenever/supply 關鍵字允許容易地構建交互式,事件驅動的應用程序。
- 懶惰求值,如果可能的話,急切求值當需要或必要時。這意味著,例如,惰性列表,甚至無限延遲列表,如斐波納契序列或所有素數。
- 原生數據類型用于更快的處理
- 使用 NativeCall 連接到 C/C++ 中的外部庫非常簡單。
- 使用 Inline::Perl5 和 Inline::Python 連接 Perl 5(CPAN)/Python 非常簡單。
- 可以同時安裝和加載模塊的多個版本。
- 由于更簡單的更新/升級策略,簡化了系統管理。
- 簡單的數值計算沒有損失精度,因為 Rats(有理數)。
- 用于解析數據或代碼的可擴展語法(Perl 6 用它解析自身)
- Perl 6 是一種非常易變的語言(定義自己的函數,運算符,traits 和數據類型,為您修改解析器)。
- 很多的數據類型選擇,加上創建自己的類型的可能性。
- 具有適當邊界檢查的多維成型的和/或原生數組
- 在某個匹配出現時, 詞法解析期間隨時執行代碼
- 添加自定義運算符或添加 trait 特征和編寫子例程一樣簡單。
- 在任何運算符(系統或自定義添加的)上自動生成超運算符。
- 運行在各種后端上。目前 MoarVM 和 JVM,JavaScript在開發中,可能會有更多。
- 執行期間(JIT)熱代碼路徑的運行時優化。
- 運行在小型(例如 Raspberry Pi)和大型多處理器硬件上。
- 基于垃圾收集:沒有及時銷毀,所以引用計數沒有必要。使用 phasers 用以及時的動作。
- 方法可以在運行時混合到任何實例化的對象中,例如。以允許添加帶外數據。
- 通過使用具有多重分派和自動生成使用信息的 MAIN 子例程,使命令行接口易于訪問。
- 更少的代碼行創建更緊湊的程序。名字的霍夫曼編碼允許更好的可讀性。
- 使用簡單的迭代器接口定義的惰性列表,任何類可以通過最小化的提供單個方法來提供。
- Perl 6 的座右銘與 Perl一直保持不變:Perl是不同的。簡而言之,Perl旨在"使容易的工作變得容易,使困難的工作變得可能"。和"條條大路通羅馬"。現在有更多 -Ofun 添加進來。
請查看 功能比較矩陣 獲取更多信息.
為什么不把它叫做除了 Perl 以外的其它東西?
很多人建議, Perl 6 跟之前的 Perl 版本的區別太大了, 我們應該考慮給它改名, 或者考慮到 Perl 6 傷害了 Perl 5, 僅僅擁有同樣的名字卻有更高的版本號.
Perl 6 仍然叫做 “Perl" 的主要原因是:
- Perl 6 仍然是一個 perlish 風格的語言, 和之前的版本遵守相同的底層思想(用于微型命名空間的符號, 條條大路通羅馬, 吸收了很多自然語言的思想..)
- Perl 6 的代碼很 perlish.
- Perl 仍然是一個強健的品牌名, 我們不想馬上拋棄它
- 找到一個替代的名字很困難. 而且, “camelia” 和 “rakudo" 不是合適的編程語言名
- 即使 Perl 6 更改了它的名字, Perl 5 也不大可能增加它的版本號為 6.因為 Perl 6 已經根植于人們的頭腦中了
Perl 6 對我來說足夠快了嗎?
那取決于你正在做什么。Perl 6 一直奉行“做對的事情然后做的更快”的哲學進行開發。對于某些東西來說它夠快了, 但是需要做的更多。
Perl 6 大部分是由志愿者開發的, 但是 Perl 6 的性能在不久的將來有待提高, 因為 MoarVM 后端包含一個現代的即時(JIT)編譯器。
Perl 5 程序員應該意識到 Perl 6 在面向對象方面有很多內建函數并且還有更多其它的。
簡單的基準測試會誤導除非你在你的 Perl 5腳本中包含了諸如 Moose, 類型檢測模塊等。
下面這個粗超的基準測試, 使用了所有諸如此類的一般說明, 能展示 Perl 6 在某些類似任務上能和 Perl 5的速度接近。
在你的系統上嘗試下, 你可能會感到很驚訝!
# Perl 6 version
use v6;
class Foo { has $.i is rw };
for (1..1_000_000) -> $i {
my $obj = Foo.new;
$obj.i = $i;
}
# Perl 5 version
package Foo;
use Moose;
has i => (is => 'rw');
__PACKAGE__->meta->make_immutable;
for my $i (1..1_000_000) {
my $obj = Foo->new;
$obj->i($i);
}
1;
# Another Perl 5 version that offers bare-bones set of features
# compared to Moose/Perl 6's version but those are not needed in this
# specific, simple program anyway.
package Foo;
use Mojo::Base -base;
has 'i';
for my $i (1..1_000_000) {
my $obj = Foo->new;
$obj->i($i);
}
1;
# A perl program which works under both perl5 (with perl -Mbigint)
# and perl6
my ($prev, $current) = (1, 0);
for (0..100_000) {
($prev, $current) = ($current, $prev + $current);
}
print $current;