Perl 6
A Quick Introduction
Solomon Foster <colomon@gmail.com>
#perl6
Perl 6
- Rethink "Perl" from the ground up
- Fix the mistakes of prior Perls
- Developed by community
- "There's more than one way to do it"
Perl 6 Online
- http://justrakudoit.wordpress.com has a list of Perl 6 links
- (That's my Perl 6 blog, lots of stuff on math, benchmarks, lists, and meta operators)
- Most important place online is the
#perl6
IRC channel on freenode
- Perl 6 development is coordinated there
- All the main developers are there pretty much every day
- A special effort is made to welcome newbies
- There is a p6eval bot present on the channel
- You can try one-liners in all the major p6 implementations
cards.pl (by Patrick Michaud)
my @suits = <♣ ♢ ♡ ♠>;
my @ranks = 2..10, <J Q K A>;
# concatenate each rank with each suit (2♣ 2♢ 2♡ ... A♠)
my @deck = @ranks X~ @suits;
# build a hash of card names to point values
my %points = @deck Z @( (2..10, 10, 10, 10, 11) Xxx 4 );
@deck .= pick(*); # shuffle the deck
my @hand = @deck.splice(0, 5); # grab first five cards
say ~@hand; # display my hand
say [+] %points{@hand}; # tell me how many points it's worth
cards.pl sample output
A♡ K♡ 3♡ 6♠ 10♣
40
Perl 6 compared to classic Perl
- Signatures for subs
- Powerful object system
- Grammars
- Smartmatching
- Switch statement (
given/when
)
- Whatever and Whatever closures
- Lazy lists
- Meta operators and defining operators
- Junctions
What about Perl 5?
- Still under active development and will be for years to come
- Some Perl 6 enhancements have been backported
-
given/when
and say
, for instance
- "Two languages from the Perl family" -- Larry Wall
What is Perl 6?
- Specification
- Multiple Compilers
(just like C, C++, Lisp, etc.)
- Test suite
- Standard Grammar (STD.pm6)
Compilers: Pugs
- First working partial Perl 6 implementation
- Developed in Haskell
- Developed by Audrey Tang
- Introduced many functional programming ideas to Perl 6
- Established much of the Perl 6 culture, like
#perl6
and -Ofun
- Now moribund
Compilers: Rakudo
- Most complete Perl 6 implementation
- Implemented in NQP (Not Quite Perl 6), Parrot, and Perl 6
- Lamentably slow
- Monthly releases
- Lead developers: Patrick Michaud, Jonathan Worthington
- New meta-model and gradual typing improvements are the current big project
- We also hope to have it running on .NET soon
Compilers: Niecza
- Fastest Perl 6 implementation
- Built on STD.pm6, the official Perl 6 grammar
- Targets .NET
- Still lacking many features Rakudo supports
- Near monthly releases
- Lead developer: Stefan O'Rear
Whirlpool Development
- Start with specification of feature
- Compiler writers attempt to implement feature
- Early adopters attempt to use feature
- Specification modified based on feedback
- Repeat
Signatures (I)
- At a basic level, not terribly impressive
- Elegantly fills a major hole in Perl 5.
-
sub fact($n) { [*] 1..$n; }
- Allows type checking:
-
sub fact(Int $n)
- and fancier checking:
-
sub fact(Int $n where { $n > 0 })
Signatures (II)
sub logarithm($num, $base = 2.7183) {
return log($num) / log($base)
}
say logarithm(4); # default base
say logarithm(4, 2);
Signatures (III)
sub swap($a is rw, $b is rw) {
($a, $b) = ($b, $a);
}
my $x = 1;
my $y = 3;
swap($x, $y);
say $x; # 3
Signatures (IIII)
sub rectangle(:$width!, :$height!, :$char = 'X') {
say $char x $width for ^$height;
}
rectangle char => 'o', width => 8, height => 4;
rectangle :width(20), :height<5>;
Signatures (V)
multi sub what(Int $x) { say "Int" }
multi sub what(Str $x) { say "Str" }
multi sub what($x) { say "Something else" }
what('foo'); # Str
what([]); # Something else
Object System (I)
- Again, basics not that impressive unless you've been stuck using traditional Perl 5 objects
- For those using modern Perl 5 objects, about the equivalent of Moose but built into the language
- Main organizing system is classes and roles
- Roles are kind of akin to Java/C# interfaces, but allow you to reuse implementation as well
- Almost everything in the language is an object now
Object System (II)
role ABC::Duration {
has $.ticks;
our method duration-to-str() {
given $.ticks {
when Int { .Str; }
when Rat { .perl; }
}
}
}
class ABC::Note does ABC::Duration {
has $.pitch;
method Str() { $.pitch ~ self.duration-to-str; }
}
Grammars (I)
- Take classic Perl's regexes to the next level
- A grammar has regex rules like a class has methods.
Grammars (II)
grammar ABC::Grammar
{
regex basenote { <[a..g]+[A..G]> }
regex octave { "'"+ | ","+ }
regex accidental { '^' | '^^' | '_' | '__' | '=' }
regex pitch { <accidental>? <basenote> <octave>? }
regex number { <digit>+ }
regex note_length_denominator { '/' <bottom=number>? }
regex note_length { <top=number>? <note_length_denominator>? }
regex note { <pitch> <note_length> }
}
Grammars (III)
- Like classes, grammars can inherit, be provided by modules, etc.
- By default, using a grammar to parse returns an AST (abstract syntax tree)
- However, you can also pass an actions object to the parser:
-
MyGrammar.parse($string, :actions($action-object))
- Actions with the same name as rules are called when the rule succeeds
Grammars (IIII)
class ABC::Actions {
method note_length($/) {
if $<note_length_denominator> {
make duration-from-parse($<top>[0], $<note_length_denominator>[0]<bottom>[0]);
} else {
make duration-from-parse($<top>[0]);
}
}
method note($/) {
make ABC::Note.new(~$<pitch>,
$<note_length>.ast,
$<tie> eq '-');
}
}
Grammars (V)
- One goal no current Perl 6 compiler achieves:
- STD.pm6, the grammar for parsing Perl 6, should be available as a core grammar
- It should also be modifiable, most notably using macros
- Lisps and Forths are the most notable languages that let you extend their own syntax
- Both have very simple syntaxes
- When this feature is fully available in Perl 6, it will join that club
Smartmatching (I)
- Smartmatching is key to a number of Perl 6's features
- You can explicitly request a smartmatch with the
~~
operator
- Smartmatch tries to do the right thing:
-
$a ~~ m/\S+/
-- run the regex on $a
, returns Match
-
$a ~~ Int
-- returns True if $a is an Int
-
$a ~~ 34
-- returns True if $a == 34
-
$a ~~ { $_.Str ne $_.perl }
-- returns result of calling closure with argument $a
-
$a ~~ 2..5
-- returns True if $a is between 2 and 5, inclusive
Smartmatching (II)
- How does it work?
- Let's look at that last one again:
-
$a ~~ 2..5
-- returns True if $a is between 2 and 5, inclusive
- Syntactic sugar for
(2..5).ACCEPTS($a)
Switch statement (I)
- Two components,
given
and when
-
given
takes an argument and a block
- It sets
$_
to its argument and then calls the block
-
when
also takes an argument and a block
- It smartmatches
$_
against its argument
- If the result is True, its block is executed
- And then control jumps out of the block enclosing the
when
Switch statement (II)
given $.ticks {
when 1 { ""; }
when 1/2 { "/"; }
when Int { .Str; }
when Rat { .perl; }
die "Duration must be Int or Rat, but it's { .WHAT }";
}
Switch statement (III)
-
given
and when
may be used independently
-
given
can be handy for setting $_
for a series of operations
-
when
can be used wherever $_
is set
-
when
is particularly handy in for
loops
Switch statement (IIII)
my $boring-lines = 0;
for $*IN.lines {
when /"Lunasa" | "Altan"/ { say "Found band!"; }
when /"fiddle" | "flute"/ { say "Found instrument!"; }
$boring-lines++;
}
Whatever
- When used as a term, we call
*
"whatever"
- It is used as a placeholder when there is no actual value
- For instance,
1, 2, 3 ... *
- That means "the sequence of natural numbers with no terminating point"
Whatever Closure (I)
- Whatever's most powerful usage is the Whatever Closure
- For normal operators -- ones where Whatever has no special meaning
- Passing Whatever as an argument creates a closure
- So for instance,
* + 1
is the same as -> $a { $a + 1 }
-
* + *
is the same as -> $a, $b { $a + $b }
-
@list.grep(* > 10)
returns all the elements of @list
which are greater than 10
-
@list.map(* + *)
returns the sum of each pair of elements in @list
Whatever Closure (II)
- Perl 6 tends to be smart about getting closure arguments
-
@a[*-1]
is the last element in @a
- If
@a[ ]
is passed a closure, it evaluates it passing the number of elements in @a as the argument
- So
@a[*/2]
is a middle element in @a
- And
@a[1..*-2]
is every element but the first and last
-
1, 1, * + * ... *
is the infinite sequence of Fibonacci numbers
Lazy lists (I)
- Wait a minute...
1, 1, * + * ... *
is infinite?!
- Yes. Used this way, the
...
sequence operator consists of
- Two starting values:
1, 1
- A rule for generating further values:
* + *
- And has no termination test (that's what the last
*
means)
Lazy lists (II)
- Perl 6 lists are lazily evaluated
- As long as you don't ask for the last element, infinite lists are fine
- Use binding (
:=
) to assign them to variables
-
my @fib := 1, 1, * + * ... *
- If I then ask for
@fib[40]
, enough elements are generated to get to the 41st Fibonacci number
- Those generated elements are remembered
- Though in the future, if a list is not bound to a variable, earlier values may be forgotten
Lazy lists (III)
- Most Perl 6 list processing functions both work with and produce lazy lists
-
@a.map
and @a.grep
both produce lazy lists, even if @a
is not lazy.
-
@fib.grep(* %% 2)
is a lazy list of all the even Fibonacci numbers, for instance
-
@fib Z @a
produces a lazy list that starts @fib[0], @a[0], @fib[1], @a[1] ...
- The
for
statement has no problem being passed an infinite list; it will loop forever unless stopped
Meta operators (I)
- One place infinite lazy lists do not work are the hyper meta operators
- The idea is that conceptually they work on the entire list at once
- Indeed, they are allowed to work on its elements in any order, and in parallel
- (In practice, none of the Perl 6 compilers handle parallel processing yet)
- Our first example of a meta operator: an operator built from a simpler operator
-
@a »+« @b
produces an array which is the sum of the other two arrays
-
@a »%%» 2
produces an array of Bools telling which elements of @a
are divisible by 2
-
~«@a
is effectively the same as @a».Str
-- it returns an array of strings
Meta operators (II)
- If you do need to sum the elements of two infinite lazy lists, you can use the zip meta operator
- Instead of
@a »+« @b
, you can do @a Z+ @b
-
Z+
evaluates the lists lazily and returns its values lazily
- It's effectively doing
(@a Z @b).map(* + *)
-
<a b c> Z~ <1 2 3>
returns a1 b2 c3
- Likewise, the cross operator
X
has a meta operator equivalent
-
<a b c> X~ <1 2 3>
returns a1 a2 a3 b1 b2 b3 c1 c2 c3
Meta operators (III)
- Another meta operator which works on arrays/lists is reduce:
-
[+] @a
sums all of the elements of @a
and returns the sum
- It's functionally equivalent to
@a[0] + @a[1] + ... + @a[*-1]
- Any infix operator can be used in place of
+
there
- Obviously this will not work for infinite lazy lists
- But there is another form of the reduce meta operator which returns a lazy list
-
[\*] 1...*
returns the lazy list 1, 1*2, 1*2*3, 1*2*3*4 ...
- That is to say, it returns each internal step of the evaluation of
[*]
Meta operators (IIII)
- Other meta operators:
- Assignment: The traditional
op=
(eg +=
)
- Negation: Infix relational operators can be used as
!op
- That is,
$a !eq $b
is equivalent to !($a eq $b)
- Reversing:
Rop
reverses the arguments to op
- So
$a R- $b
is the same as $b - $a
Meta operators (V)
- "Naturally," meta operators can be nested
-
<a b c> X~ <1 2 3>
is a1 a2 a3 b1 b2 b3 c1 c2 c3
-
<a b c> RX~ <1 2 3>
is 1a 1b 1c 2a 2b 2c 3a 3b 3c
-
<a b c> RXR~ <1 2 3>
is a1 b1 c1 a2 b2 c2 a3 b3 c3
- That's one of the few useful applications of this I know of :)
Creating new operators
- New operators can be defined just like any other sub
-
multi sub infix:<+>(MyInt $a, MyInt $b)
overloads addition for MyInt
-
sub postfix:<!>(Int $a) { [*] 1..$a; }
creates a factorial operator:
-
5!
yields 120
, just as you would expect
-
sub prefix:<$$$>($a) { "$a billion dollars" }
-
$$$10
yields the string 10 billion dollars
- In theory, these new operators can be used with meta operators too
A word about operators (I)
- You may have the impression that Perl 6 is operator crazy
- If so, you are right
- Part of the Perl 6 philosophy is to have a very rich set of operators
- It's up to programmers not to abuse this
- eg As an infix,
+
(by itself) should always refer to mathematical addition
- But that's a convention, not a hard technical rule of the language
A word about operators (II)
-
prefix:<+>
is just sugar for calling an object's Numeric
conversion method
- Operators which start with
+
are numeric operators
- For instance,
+&
converts both its arguments to Int
and does bitwise AND on them
-
prefix:<?>
is sugar for .Bool
, and ?|
converts its arguments to Bool
and ORs them
-
prefix:<~>
is sugar for .Str
, conversion to a string
Perl 6 Online Again
- http://justrakudoit.wordpress.com has a list of Perl 6 links
- Most important place online is the
#perl6
IRC channel on freenode
- Thanks!