=head1 TITLE Run Perl 6 Today! 今天開始玩 Perl 6! =head1 BLURB For a while, you could have thought Perl 6 was vaporware. It isn't. You can install Pugs and run Perl 6 programs in five minutes. 有好一陣子,你可能認為 Perl 6 一直還沒實現。事實並非如此。你可以花五分鐘安裝 Pugs 並且執行 Perl 6 程式。 (This isn't a module; It's an article to appear in the December 2005 issue of I.) (這並不是一個模組,這是一篇出現在2005年12月 I 的一篇文章。 =head1 BODY Perl 6 is an incredibly fun language to play with. It isn't finished yet, and in fact for a while it looked like it would take forever to arrive. But thanks to the Pugs project, you can try it out right now and start hacking Perl 6 straight away. Perl 6 是個讓人越玩越有趣的一個程式語言。它還沒結束開發,而且事實上,這一段時 間看來,它像是永遠也不會有終點。不過感謝 Pugs 開發團隊,你現在就可以試玩看看, 而且開始hacking Perl 6。 =head2 First things first =head2 最開始該做的 [[ This section could be placed in a sidebar. If so, the previous paragraph should point to it. ]] If you're on *nix, one of these commands should get you up to speed: 假如你正在使用 *nix,下列的其中一行指令應該會幫助你加快腳步: apt-get install pugs pugs-doc pugs-modules # Debian pkg_add pugs # FreeBSD emerge pugs # Gentoo On Windows, you can fetch the PxPerl binary distribution from this site: 在 Windows 中,你可以從這裡抓取 PxPerl 的執行檔: http://www.pxperl.com/?pxperl If your OS isn't one of the above, or if you want to build pugs yourself, you'll need the latest GHC compiler from L, and then install L via CPAN, like a standard Perl 5 module. Compiling pugs takes a lot of memory, so try this on a strong machine. 如果你所使用的並不是上述的作業系統,或者你想要自己手動編譯 Pugs 的話。你會需要從 L 取得最新版的 GHC 編譯器,然後就像安裝其他 Perl 5 模組一樣的從 CPAN 安裝 L。編譯 pugs 需要耗費大量的記憶體,所以也 許你該找一部夠力的機器來進行。 =head2 What's in the box? =head2 機器裡有什麼? You get B, the experimental compiler for Perl 6. Along with it come plenty of short example programs, some modules, and documentation. B can run programs from files and via the B<-e> switch, just like B, but it also has an interactive mode which is great for quick things. In Perl 5, you'd probably run C for this; here, just run it with no parameters. You'll get a welcome banner and a prompt. 你拿到了 B,還沒經過測試的 Perl 6 編譯器。同時附有一些很短的範例程式,一些模 組以及文件。B 可以透過檔案的方式來執行程式,或是使用 B<-e> 選項,就像 B 一樣,不過它也可以使用互動模式,這實在是很讚,而且快速的事情。在 Perl 5,你可能執行 C 來達到這樣的情況,不過現在只要執行 B 時不帶任何參數,你將可以 看到歡迎的標題跟一個提示字元。 [[ The screenshot is optional :-) ]] $ pugs ______ /\ __ \ \ \ \/\ \ __ __ ______ ______ (P)erl6 \ \ __//\ \/\ \/\ __ \/\ ___\ (U)ser's \ \ \/ \ \ \_\ \ \ \/\ \ \___ \ (G)olfing \ \__\ \ \____/\ \____ \/\_____\ (S)ystem \/__/ \/___/ \/___/\ \/____/ /\____/ Version: 6.2.10 \/___/ Copyright 2005 by Autrijus Tang -------------------------------------------------------------------- Web: http://pugscode.org/ Email: perl6-compiler@perl.org Welcome to Pugs -- Perl6 User's Golfing System Type :h for help. Loading Prelude... done. pugs> We are now ready to run our canonical first Perl 6 program: 現在我們準備開始執行第一個 Perl 6 程式: pugs> say "Hello, world!" Hello, world! bool::true pugs> The C builtin works just like C, but puts a newline at the end. You'll find there are many small improvements of this sort. Since we are in an interactive environment, we also got the result of the whole expression we'd evaluated; in this case the print was successful, so it returned a true boolean value. You can also run this program from the command line. Would it be Perl if you couldn't? 內建的 C 就像 C 做的事一樣,不過它在最後加上了一個換行符號。你將會發 現 pugs 有很多像 因為我們正在互動模式的環境底下,我們會馬上拿到整個敘述句所得到的結果。在這個例子中, 我們成功的列印了。所以它傳回一個結果為真的布林值。你也可以在命令列中執行它。假如不行 的話,它還能算是 Perl 嗎? $ pugs -e 'say "Hello, world!"' Hello, world! $ If you like OOP, you'd be pleased to see that this works as well: 如果你喜歡使用物件導向的程式設計,你可以看到這樣的寫法也可以運作: "Hello, world!".say; [[ Not sure the following bit isn't too much of a digression at this point. I'd like to make the point about lists being candidates for method invocation but maybe arrange this to come later. ]] As does this: 還有這樣: "Hello, world!".split("").join("").say; Everything can be used like an object in Perl 6. In the last example, the string is getting the C method invoked on it; the result, a list, responds to the C method and returns a string, which is printed by C. Of course, you could spell this in longhand the same way as you could in Perl 5: 在 Perl 6,所有的事情都可以被以物件的方式來使用。在最後一個例子中,C 對 字串產生作用,得到的結果是一個串列,並且把串列傳回給 C 這個方法,而且傳回 一個字串,最後再用 C 印出來。當然,你可以自己用手工慢慢打出在 Perl 5 中的 寫法: my $original = "Hello, world!"; my @characters = split //, $original; my $rejoined = join "", @characters; print $rejoined, "\n"; [[ (EM) this seems overstating it to me... the real P5 equivalent would be: print join("",split //,"Hello, world!"),"\n"; ]] [[ (GY) sure. This section needs work; I was steering this towards the point below that this isn't "just" a chain of builins, it's a chain of builins dispatched as methods. Leaving for now until I word it better. ]] # This code is valid Perl 5 and Perl 6. You will often # find Perl 5 code works as is, or with little modification, # in Perl 6.) But aggregates can be treated like objects too, so C<@characters.join("")> works in Perl 6 where C<< @characters->join("") >> didn't in Perl 5. (Yes, C<< -> >> is uniformly a dot now.) [[ End digression. ]] =head2 Who's this new dog? [[ XXX: WRITEME ]] =head2 A Catalog of Cool Perl 6 offers many cleanups and rationalizations over Perl 5, as well as some shiny new features. If you've been programming Perl 5 for a while you may have gotten used to some quirks of the language, so much that you don't see what the fuss is about and why you'd like to switch. I'll list just a few things, and limit myself to what Pugs already supports. =over 4 =item Function signatures Up until now, subs in Perl didn't have much by way of formal parameter specification. Sure, this made them very flexible (take a C<@_> and do whatever you like with it), but it also meant that for fairly straightforward things like argument validation or default values you had to write code yourself, or rely on on an external module. Take the following (Perl 5) code: sub make_car { my $model = shift || die "no model"; my $color = shift || "black"; my $doors = shift || 4; # ... Expressing parameters is flexible, yes, but it's also tedious. Even where there are no default values there can be trouble: for example, if you decide you don't like multiple calls to C and consistently code in this style: sub my_func { my($foo, $bar, $baz) = @_; # ... Beginners (and insufficiently caffenated late-night hackers) can easily make one of the following disastrous mistakes: my ($foo, $bar, $baz); # oops, forgot " = @_" my ($foo, $bar, $baz) = shift; # oops, used shift() instead of "@_" my $single_arg = @_; # oops, will usually be 1 The Perl 6 compiler has syntax to save you from all this. Here's how you spell out the car example: sub make_car ($model, $color? = "black", Int $doors? = 4) { ... } This single line does more than the four Perl 5 lines did. First, it specifies that the function receives three parameters, one of which is mandatory. The C in C<$black?> and C<$doors?> means they are optional; in both cases default values are supplied. (You don't have to give one: the default default is undef.) The C mark on the last parameter means calling the function with a non-integer will raise an error. As you can see, this is an optional feature: you don't have to declare types everywhere. How is this make_car used? These are obvious: [[ (EM) Maybe source code examples should adhere to PBP ?? ]] make_car("VW Beetle", "green", 2); make_car("Ford Model T"); # black, 4-doored make_car(); # error: model not supplied make_car("Fiat", "Red", 3, "sunroof"); # error: too many args But there's more. Ever used a library that has functions with many parameters? It can get kind of hard to keep track of their order. This is why many complex libraries use hashes for named args, but coding up validation for that is once again tedious. Perl 6 lets I function be called with named args automatically: make_car(doors => 2, model => "VW Beetle") $widget.add_accelerator(signal => "clicked", group => $accel_group, key => GDK_n, mods => GDK_MOD1_MASK, flags => GTK_ACCEL_VISIBLE); You've probably seen Perl 5 functions that go out of their way to accept either positional args, or a hash or hashref with named args. There's no need to do that any more. If you have a function you'll be calling many times with a changing set of arguments, you can keep them in a hash and use the "splat" operator to flatten it: sub make_many_cars ($howmany) { my @cars; for 1 .. $howmany { # the parens can be omitted here in Perl 6 my %car_prefs = get_user_prefs(); push @cars, make_car(*%car_prefs); } return @cars; } =item Lightweight closure syntax Every block potentially acts like a closure in Perl 6, and the syntax is at once simplified (you don't need to say C to declare anonymous pieces of code) and extended to include formal parameters. my $beeper = { say "beep!" }; # $beeper is a coderef. No need for "sub". $beeper(); # says "beep!". No p5ish "->" here. my $square = -> $x { $x * $x }; # use "->" to introduce args my @squares = map $square, 1 .. 10; Control structures typically take closures, so you can, as in the example below, iterate with C with more than one element every time. C is a function that takes a few lists and returns interleaves their elements: for zip @Xs, @Ys -> $x, $y { push @differences, $x - $y; } Of course, this kind of thing is usually better expressed with map, which can also take more than one element at a time. # Infix "¥" means the same thing as "zip"; this is a visual analogy. # See the sidebar on Unicode operators for details. my @differences = map -> $x, $y { $x - $y }, @Xs ¥ @Ys; There's even a feature for the extremely lazy: formal parameters with no predeclaration. Variables mentioned in a closure that have the C<^> secondary sigil (called "twigil" in Perl 6 speak) are all inferred as parameters to the block. my @differences = map { $^x - $^y }, @Xs ¥ @Ys; How does this compare with Perl 5? If C<@Xs> and C<@Ys> can be assumed to be the same length, then this isn't too bad, though the explicit subscripting does make it less elegant: my @differences = map { $Xs[$_] - $Ys[$_] } 0 .. $#Xs; If we want to allow for lists of different length, though, we need a solution that's much more involved: sub map2 (&@) { my ($code, @list) = @_; my @output; while (@list) { my($x, $y) = splice @list, 0, 2; push @output, $code->($x, $y); } return @output; } sub zip2 (\@\@) { my($Xs, $Ys) = @_; my @output; for my $i (0 .. max(scalar(@$Xs), scalar(@$Ys))) { push @output, ($i < scalar(@$Xs) ? $Xs->[$i] : undef), ($i < scalar(@$Ys) ? $Ys->[$i] : undef); } return @output; } sub max { $_[0] > $_[1] ? $_[0] : $_[1] } my @differences = map2 { $_[0] - $_[1] } zip2(@Xs, @Ys); This took care of throwing undef instead of missing values from the shorter list, while not growing the original. It even uses some fancy prototypes to avoid gratitious syntax (the C keyword and reference-taking backslashes). It is much longer than the Perl 6 version, but also less efficient (two temporary copies of the whole data are created in memory -- the Perl 6 version never allocates even I extra copy). Since we used prototypes, the utility functions need to be declared above the actual code (or stowed in a module, of course). But the strongest point against this is how it isn't extensible; if you wanted to take the differences of elements in I lists, you'd need to write more support code. In Perl 6, you just say my @differences = map { $^x - $^y - $^z }, @Xs ¥ @Ys ¥ @Zs; =item Many (but systematically arranged) operators If non-ASCII operators and parameters that don't need to be declared haven't blown your mind yet, good. The two-list difference operation from the last section could also be written like this:[1] my @differences = @Xs »-« @Ys; C<< »« >> are "hyperoperators" that take a regular operator and "lift" it to work on lists. You can still use them when you don't have I lists: my @halves = @original »/« 2; # 2 is upgraded to "(2, 2, 2, ...)" Relatedly, there's a way to "reduce" long expressions such as sums or products with the C<[]> metaoperator: my $sum = [+] (1, 2, 3, 4); # 1 + 2 + 3 + 4 my $prod = [*] (1, 2, 3, 4); # 1 * 2 * 3 * 4 If these sound a little too abstract, rest assured that they do become quite handy after you get used to them. Let's introduce two nice and less funky operators. The first is a new syntax for quoting words, similar to Perl 5's C: my @suspects = ; Like C in Perl 5, C<< <...> >> single-quotes its arguments. If you want interpolation, you can use the C<< «...» >> variant. The second convenient new operator is C, the "and-if-not-defined" operator. You'd typically use it like this: my $output_file = lookup("output_file") // $DEFAULT_FILENAME; In Perl 5, you might use C<||> but risk the gotcha of the config value being set to a file called "C<0>". You'd have to spell this the long way: my $output_file = defined lookup("output_file") ? lookup("output_file") : $DEFAULT_FILENAME; This becomes especially annoying when you want to check in more than one place (for example, what if you can also get the output file from an environment variable?). Which brings me to the point of the digression, which was to suggest that if you had a function to C a suspect, you could talk to them one by one until you had an answer: my $answer = [//] map &interrogate, ; It's important to note that unlike Perl 5, map is I, which means it only "eats up" one element of input as an element of output is required. In this case, Verbal may not feel the heat at all if (say) McManus talks first.[2] Another developement that's taken palce is the normalization of bitwise operators. Where you once had C<$x | $y> mean different things depending on whether the two variables were numbers or string -- with the kludgy C<(0+$x) | (0+$y)> workaround guard to force numeric interpretation -- the operators now explicitly state what kind of context they impose. This means that the amount of operators is large, but it is very clear what they do. The idea is that these operators now take a mandatory prefix: C<+>, C<~>, or C; they mean numeric, string, or boolean context. # Perl 5 print 7 & 54; # 6 print "7" & "54"; # "5" # Perl 6 print 7 +& 54; # 6 print "7" +& "54"; # 6 print 7 ~& 54; # "5" print "7" ~& "54"; # "5" [[ more: mention C<.> again, and C<~>. We don't want to turn into S03 here but these things are all pretty prominent when someone sees p6 code for the first time. ]] =item Junctions Now that C<|>, C<&>, and C<^> no longer mean bitwise operations, they are free to be used for something else: junctions. These are several values lumped up into one. They are useful in clarifying logic expressions: my $options = '--help' | '-d' | '-e'; if all($x, $y, $z) eq $options { ... } [[ XXX: this example is stolen from Autrijus's Apocalypse Now talk. Maybe think of something else? ]] =item Cleaned-up OOP When version 5 introduced object oriented programming to Perl, it did so with a minimal change to the existing syntax. It also mandated very little about how objects are arranged: the vast majority of Perl 5 classes pick blessed hashes for their all-around usefulness, but the object system itself is flexible and can use other things, such as arrays or even globs. Certainly this has afforded authors with great creativity and power, but it has also made learning Perl OOP a little more difficult than it needed to be. If you do use the de-facto standard of hash elements for object fields, you are at risk of falling for some of the most frustrating bugs, the kind you don't feel you'd learned anything from after you'd spent hours hunting them down: $self->{colour} = "red"; print $self->{color}; # oops! By rights, this should be something the compiler catches, and in Perl 6, it is. Classes are more than "just" packages. Instance variables are declared with the new C keyword: class Car; has $.model; has $.color; has Int $.doors; For this money, you get a constructor with basic initialization, and three automatic accessors that can act as lvalues. my $wheels = Car.new(model => "Fast 'un"); $wheels.doors = 2; $wheels.color = "red"; If you want, you can provide your own C method that has the class-specific smarts (say, give a default color, or limit cars to a certain number of doors). The C<.> twigil meant the members above were public (and so they had accessors created for them which are visible outside the class. You can also declare private members: has Int $!odometer; # note "!" twigil, meaning "private". has Location $!loc; # let's assume there is a Location class. # ... $wheels.odometer -= 100; # nice try, but it won't work. Methods are now declared with a keyword of their own. This distinguishes them from regular Cs, and also means that you don't have to declare the invocant (by convention often called C<$self> or C<$this> in Perl 5) yourself. method beep { say "beep!" } method drive (Location $destination) { $!odometer += $!loc.distance($destination); $!loc = $destination; self.beep; } There is, of course, much more to OOP in Perl, but there's no room to discuss it here. We'll just mention the idea of Roles, where a class declares what kind of things it I. Part of the implementation of a class may be taken directly from the providing Role. It works differently from inheritance and is worth looking into. =back =head2 SIDEBAR: Confused by Unicode? Perl 6 defines a few operators that aren't ASCII, though they all have ASCII fallbacks. Here's the current (short) core list: Op Fallback Meaning «...» <<...>> Interpolating word quotes ¥ Y or &zip Zip lists together Since it's easy to add new operators, expect mathematical modules to say things like ⌈$PI⌉ to mean 4. [[ Those are Unicode LEFT CEILING and RIGHT CEILING, U+2308 and U+2309. They look just like square brackets with the lower serifs sawn off. Sorry about the pain it must be to include this, it's worth mentioning since this kind of thing is definitely going to show up in Perl 6 code. ]] The file C in the pugs distribution explains how to type Unicode in popular editors. =head2 The C directory When you install B, you get plenty of (working) example code. Let's look at a few of the things there. =head3 examples/network/http-client.p6 #!/usr/bin/pugs use v6; say "*** Fetching from the Jerk It (tm) RSS feed..."; my $hdl = connect("www.phreeow.net", 80); $hdl.say( "GET /cgi-bin/jerkme.rss HTTP/1.0\n", "Host: www.phreeow.net\n" ); $hdl.flush; if ($hdl.slurp ~~ rx:perl5{(.+)\s*}) { say $0; } else { say "*** Oops, connection failed." } This example -- one of pugs' oldest, added two months after the project started -- is a very simple web client. The code is fairly straightforward, but it illustrates a few features of Perl 6 and of pugs. First, you'll notice that C returns an object that's used in a totally OOPish way. At the time this was added, networking wasn't fully specced: expect this to be called something like C in the official perl6 release (though there very well maybe an C-ish way to create lazyily defined IO objects as well). Pugs just went away and implemented a reasonable approximation. The client speaks very simple HTTP, C<.flush>es the request to make sure it's sent over the wire, and analyzes the response. This line is worth breaking down: if ($hdl.slurp ~~ rx:perl5{(.+)\s*}) { ... } # Perl 5 equivalent sub slurp { local $/; readline shift } # works on open filehandles only my $response = slurp($hdl); if ($response =~ m{(.+)\s*}x) { ... } The basic idea is clear -- get the whole HTTP response, perform a capturing pattern match. There are a few important details though. First, both P5 and P6 versions of the code use Perl 5 regular expressions for the match. Perl 6 defines a new language called Rules, but an implementation wasn't available when this code was written so P5 regexp were used. As you can see, these are accessible through C, which is the C Rule keyword with the Perl 5 I attached to it. [[ XXX: not sure if this is worth the break in pace-- You omit the modifier if you want a P6 rule; and just like you can omit C in Perl 5 if you just want to C, you could do the same if you were using C as your delimiters. In full Perl 6, this line becomes: ..and then port the regexp to a rule, which kinda shows XML is annoying to pattern match quickly and dirtily. So maybe skip this. ]] Regardless of which pattern engine is used, the capture, if successful, goes to C<$0> and not C<$1> as it would in Perl 5. The other difference is that instead of using C<~=>, we now use C<~~> to match. The change is not just one of spelling: C<~~> is the shiny new I operator, which has very well-defined semantics for matching anything against anything else. That is, you know in advance what it'd do if you say something like C<%hash ~~ @array> or C<$dow ~~ 0 .. 7>. =head3 examples/games/animals.p6 $ ./pugs examples/games/animals.p6 Is it a dog (yes/no)? n No!? What was it then? cat And a question that distinguishes a dog from a cat would be? Does it purr? And for a cat, the answer would be... (yes/no)? y Play again? (yes/no)? y Does it purr? (yes/no)? y Is it a cat (yes/no)? y I got it! Play again? (yes/no)? n Bye! {('no' => 'dog'), ('question' => 'Does it purr?'), ('yes' => 'cat')} $ The code for this simple guessing game is just a little too long to fit here, so I'm just going to hilight some nice features. The program tries to guess what animal you are thinking of; if it fails it asks for distinctive knowledge it can use next time. Obviously, this knowledge is expressed in some data structure: the nice thing about this example is that the last thing it does when exiting is dump this structure. Or rather, the really nice thing about this is the code to do it: say $info.perl; C<.perl> is similar to C, but is built into perl. It provides sensible serialization for objects as well. If the pugs hackers have their way, you can expect an analogous C<.yaml> method too (though it may not be in the core). Recall the smart match operator from the previous example, and let's look at this snippet of code: given $input { when "y" { return 1;}; when "n" { return 0;}; default { return yes($q) }; } This is Perl 6's switch statement. C sets C<$_> (the I as it's now called) to be C<$input>, and thenruns the code in the block. Each C block performs a smart match against the topic -- it's shorthand for something like if $_ ~~ "y" { return 1; } else { ... } The beauty of this construct is that smart matches work on I, so you can have code like this: given $food { when "My tortilla" { say "hey! give it back!" } when Pizza | Lazagna { .eat } when .caloric_value > $doctors_orders { warn "no, no no" } # XXX: make this work } =head2 More information L - The Pugs homepage. Contains links to code and binaries, presentations and talks, journals and news, automatic smoke test results. L - PlanetSix aggregates the development journals of leading Perl6/Pugs personnel, as well as semiweekly summaries of the Perl 6 mailing lists. L - Subversion repository of the pugs code, which you can browse with a web client. Check out the C folder! The C<#perl6> channel on C - Come hang out with the hackers! This channel seldom sleeps as developers come from all around the world. L - The Perl 6 Synopses are summaries of the longer Apocalypse and Exegesis documents, and are more up-to-date. In fact, they function as a specification for Perl 6 implementations, Pugs included. They are, like Pugs, work in progress. =head1 FOOTNOTES [1] Yes, C<<< @Xs »-« @Ys »-« @Zs >>> also works. [2] C is scheduled for inclusion in perl 5.10. For those interested, patches are available for existing version all the way back to 5.6. =head1 AUTHOR INFORMATION This article was written by Gaal Yahas ELE with the help and inspiration of #perl6. It is distributed under the Creative Commons Attribution-ShareAlike 2.0 license L. Thanks to Eric Hodges and Elizabeth Mattijsen for material suggestions. =cut