Perl 6 Is Fun

来源:互联网 时间:1970-01-01


I’ve been writing a fair bitof Perl 6 lately, and my main takeaway so far is that Perl 6 is fun.

Pretty much everything I love in Perl 5 is still part of Perl 6, but almost everything I hate is gone too. $Love - $Hate = $Fun.

Here are some of the things that I’ve been having fun with in Perl 6 …

Built-In OO and Types

I really love that I can write this in native Perl 6:

Perl

use v6;unit class Pod::To::HTML::Renderer is Pod::To::HTML::InlineListener;has Cool $!title;has Cool $!subtitle;has Cool $!prelude;has Cool $!postlude; usev6;unit classPod::To::HTML::RendererisPod::To::HTML::InlineListener; has Cool$!title;has Cool$!subtitle;has Cool$!prelude;has Cool$!postlude;

Of course, you can already do pretty much the same thing with Moosein Perl 5, except now I don’t have to debate Moose vs Moo vs Moops vs STOP MAKING SO DARN MANY “M” MODULES!

Roles work just as well with a simple role Foo { ... }declaration.

Multiple Dispatch

If you’ve ever written an API for parsing a text format as a stream of events in Perl 5, you’ve probably ended up with something like this:

Perl

sub start_bold { ... }sub end_bold { ... }sub start_heading { ... }sub end_heading { ... } substart_bold{...}subend_bold{...} substart_heading{...}subend_heading{...}

And of course to dispatch it you write something like this:

Perl

sub dispatch { my $self = shift; my $node = shift; my $type = $node->type; my $start = 'start_' . $type; my end = 'end_' . $type; $self->listener->$start($node); ... # deal with node contents $self->listener->$end($node);} subdispatch{my$self=shift;my$node=shift;my$type=$node->type;my$start='start_'.$type;myend='end_'.$type;$self->listener->$start($node);...# deal with node contents$self->listener->$end($node);}

That’s not terrible, but it’s so much more elegant with multiple dispatch in Perl 6. Here’s our listener with multiple dispatch:

Perl

multi method start (Node::Bold $node) { ... }multi method end (Node::Bold $node) { ... }multi method start (Node::Heading $node) { ... }multi method end (Node::Heading $node) { ... }# And let's catch unexpected nodesmulti method start (Any:D $node) { ... }multi method end (Any:D $node) { ... } multi methodstart(Node::Bold$node){...}multi methodend(Node::Bold$node){...} multi methodstart(Node::Heading$node){...}multi methodend(Node::Heading$node){...} # And let's catch unexpected nodesmulti methodstart(Any:D$node){...}multi methodend(Any:D$node){...} given/when and smartmatching

There was an attempt to put this in Perl 5 but it never worked out because this feature really needs a solid type system and ubiquitous OO to work properly.

Perl

method walk-pod (Any:D $node, Int $depth = 0) { self!maybe-end-all-lists( $node, $depth ); given $node { when Array { # Array is a type name - this is like $node->isa('Array') in Perl 5 self.walk-pod( $_, $depth + 1 ) for $node.values; } when Pod::Item { # same again ... } default { self!send-events-for-node( $node, $depth ); } }} method walk-pod(Any:D$node,Int$depth=0){self!maybe-end-all-lists($node,$depth);given$node{whenArray{# Array is a type name - this is like $node->isa('Array') in Perl 5self.walk-pod($_,$depth+1)for$node.values;}whenPod::Item{# same again...}default{self!send-events-for-node($node,$depth);}}}

Smartmatching also dovetails nicely with Perl 6’s junctions:

Perl

given $node.name { when 'Image' { ... # do something with an image } when any <Html Xhtml> { ... # do something with HTML } when any @semantic-meta-blocks { self.handle-semantic-block( $node, :meta ); }} given$node.name{when'Image'{...# do something with an image}whenany<HtmlXhtml>{...# do something with HTML}[email protected]{self.handle-semantic-block($node,:meta);}} Easy Threading

Want to split up a task across many threads? It’s incredibly easy!

Perl

method !run-with-progress ($items, Routine $sub, Str $msg = q{ done}) { my $prog = Term::ProgressBar.new( :count( $items.elems ), :p ) if $!verbose; my $supply = $items.Supply; if $!threads > 1 { my $sched = ThreadPoolScheduler .new( :max_threads($!threads) ); $supply.schedule-on($sched); } my $i = 1; $supply.tap( sub ($item) { $sub($item); $prog.?update($i); $i++; } ); $prog.?message($msg);} method!run-with-progress($items,Routine$sub,Str$msg=q{ done}){my$prog=Term::ProgressBar.new(:count($items.elems),:p)if$!verbose;my$supply=$items.Supply;if$!threads>1{my$sched=ThreadPoolScheduler.new(:max_threads($!threads));$supply.schedule-on($sched);}my$i=1;$supply.tap(sub($item){$sub($item);$prog.?update($i);$i++;});$prog.?message($msg);}

This method takes a list (or sequence) of $items. If you told the code to run with more than one thread, then it uses the built-in ThreadPoolSchedulerand Supplyrole to iterate over the items and run them in the given Routine.

Built-in lock-safe threading in about 13 lines of code (ignoring the progress bar bits)!

So Many Little Things

Did you catch that $prog.?update($i)call in the method above? If $progis defined, it calls the method, otherwise it does nothing.

And I haven’t even had a chance to use features like grammars, built-in set operations, or a native call interfacethat lets you define the mapping between Perl 6 and C with some trivial Perl 6 code. If you’ve ever written XS you will appreciate just how wonderful that interface is!

Also, the Perl 6 community has been great to work with, answering all my quetsions (dumb or not), and even improving an error message within about 10 minutes of my suggestion that it was unclear! Of course, the Perl 5 community is pretty great for the most part too, so that’s nothing all that new (although no one can patch anything in the Perl 5 core in 10 minutes ;).



相关阅读:
Top