Share
Embed
Perl 6 - The Butterfly Has Landed
An overview of Perl 6 and some of its features. Created and presented by Michał Wojciechowski.
Sidnet
February 29, 2016
Transcript
73 slides
-
2/73 Not a “Perl 5 ++” • Perl 6 and
Perl (5) are different languages • Sometimes called “sister languages”, belonging to the same family • They share many concepts, but are not compatible • Still, “Perl 6 is Perl” -
3/73 Some History • Designed by Larry Wall (creator of
Perl (1-5)) • Language design started in 2000 • First intention was to get it ready in ~2 years • It actually took 15 years • - When will Perl 6 be released? - On Christmas! • Released in December 2015 (on Christmas) -
5/73 Perl 6, Say Hello! • “Hello World” in Perl
6: • As an oneliner: #!/usr/bin/env perl6 say 'Hello, World!' $ perl6 -e 'say "Hello, World!"' -
6/73 Glossary/Bestiary • Perl 6 is the language specification (with
the official test suite) • NQP (Not Quite Perl) is a subset of Perl 6 • Rakudo is a Perl 6 (and NQP) compiler • Rakudo Star is a Rakudo distribution • MoarVM is a virtual machine (runtime) • Rakudo can also target JVM (Java runtime) -
9/73 Basic Syntax • if and unless: if $day eq
'Saturday' || $day eq 'Sunday' { say 'You should not be working today.'; } elsif $hour !~~ 9..16 { say 'You should not be working at this hour.' } else { say 'Work work work!'; } unless $day eq 'Monday' { say "Yay! It's not Monday!"; } -
10/73 Basic Syntax • with (like if defined): • given/when:
with $score { $high_score = $score if $score > $high_score; } else { say "Score is not set"; } given $score { when 0..100 { say "You suck"; } when $_ > 9000 { say "IT'S OVER 9000!!!!11"; } default { say "Meh" } } -
11/73 Basic Syntax • for: • loop (C-style for): loop
(my $n = 10; $n > 0; $n--) { say $n; sleep 1; } say "Ignition!"; my @pets = ('cat', 'dog', 'hamster', 'porcupine'); for @pets -> $pet { say "One of my pets is a $pet"; } -
12/73 Basic Syntax • while and until: • repeat while
(and repeat until): while $foo < 3 { $foo++; } until $foo > 6 { $foo++; } repeat { $foo++; } while $foo < 3; -
13/73 Basic Syntax • Comments: # Single line comment =begin
explanation Multiline comment =end explanation say #`( Embedded comment ) "Hello!"; #`( Embedded comments can also be used for multiline comments ) -
15/73 Basic Data Structures • Scalars: • Arrays – autoextending:
• Arrays – fixed-size: my $foo = 42; $foo = 3.14159; $foo = 'Om nom nom'; my @musketeers[3] = [ 'Athos', 'Porthos', 'Aramis' ]; @musketeers[3] = "D'Artagnan"; # Index 3 for dimension 1 out of range (must be 0..2) my @dinosaurs = [ 'Stegosaurus', 'T-Rex' ]; @dinosaurs[2] = 'Velociraptor'; -
16/73 Basic Data Structures • Arrays – multidimensional: • Hashes
(key/value pairs): my @chessboard[1..8;1..8]; @chessboard[4;1] = '♕'; my %edges = (triangle => 3, square => 4, pentagon => 5); %edges{'hexagon'} = %edges{'pentagon'} + 1; say %edges<hexagon>; # 6 -
17/73 Ranges • Used to generate lists of consecutive numbers
or strings: say [1 .. 5]; # [1 2 3 4 5] say [1 ^.. 5]; # [2 3 4 5] say [1 ..^ 5]; # [1 2 3 4] say [1 ^..^ 5]; # [2 3 4] say [^5]; # [0 1 2 3 4] my @alphabet = 'a' .. 'z'; say @alphabet[5 .. 10]; # (f g h i j k) say @alphabet[^5]; # (a b c d e) -
18/73 Lazy Lists • List values aren't calculated until needed
• Can be “infinite”: • Lazy lists made from other lazy lists: my @ints = 1 .. Inf; say @ints[12345]; # 12346 my @even_ints = grep * % 2 == 0, @ints; say @even_ints[12345]; # 24692 my @squares = map * ** 2, @ints; say @squares[12345]; # 152423716 -
19/73 Sequence Operator • Perl 6 can deduce what arithmetic/geometric
sequence should be generated: • If it's unable to guess, we can tell it explicitly: my @numbers = 10, 20 ... *; say @numbers[^5]; # (10 20 30 40 50) my @powers_of_2 = 1, 2, 4 ... *; say @powers_of_2[^5]; # (1 2 4 8 16) my @seq = 1, { 2 * $_ + 3 } ... *; say @seq[^5]; # (1 5 13 29 61) -
21/73 Types • Perl 6 is gradually typed, allowing for
both dynamic and static typing • Comes with many built-in types, e.g.: – Int, Num, Complex – Str, Bool – Array, Hash, Pair – Regex, Code, Routine -
22/73 Types • Dynamic typing: • Static typing: my $foo
= 1.23; say $foo.WHAT; # (Rat) $foo = 'Bar'; say $foo.WHAT; # (Str) my Rat $foo = 1.23; $foo = 'Bar'; # Type check failed in assignment to $foo; # expected Rat but got Str -
23/73 Subsets • Easily defined “subtypes” • Created by adding
constraints to types: • Can be used ad-hoc (not named): subset EvenInt of Int where * % 2 == 0; my EvenInt $foo = 3; # Type check failed in assignment to $foo; # expected EvenInt but got Int sub hello(Str $name where *.chars > 0) { say "Hello, $name!"; } -
25/73 Subroutines • Simplest example, no arguments: • Can be
called with or without parentheses: • Without return, the last value is returned: sub hello { return "Hello, World!"; } say hello(); say hello; # Hello, World! (x2) sub hello { "Hello, World!"; } -
26/73 Subroutines • Subroutine with an argument: • With an
optional argument: sub hello($name) { "Hello, $name!"; } say hello('Chris'); # Hello, Chris! sub hello($name?) { "Hello" ~ (", $name" if $name) ~ "!"; } say hello('Martin'); # Hello, Martin! say hello; # Hello! -
27/73 Subroutines • Argument with a default value: • Default
value using a preceding argument: sub hello($name = 'World') { "Hello, $name!"; } say hello; # Hello, World! say hello('Jacob'); # Hello, Jacob! sub hello($name, $bangs = $name.chars) { "Hello, $name" ~ "!" x $bangs; } say hello('Mike'); # Hello, Mike!!!! -
28/73 Subroutines • Argument with a type constraint: • Subroutine
declared with a return type: sub hello(Str $name) { "Hello, $name!"; } say hello(321); # Calling hello(Int) will never work with declared # signature (Str $name) sub hello(Str $name) returns Str { "Hello, $name!"; } -
29/73 Subroutines • Named argument: • Mandatory named argument: sub
hello($name, :$title) { "Hello, " ~ ("$title " if $title) ~ "$name!"; } say hello('Tom', title => "Mr."); # Hello, Mr. Tom! sub hello($name, :$title!) { "Hello, $title $name!"; } say hello('Tom'); # Required named parameter 'title' not passed -
30/73 Subroutines • Slurpy argument: • Read/write argument: sub hello(*@names)
{ "Hello, " ~ join(", ", @names) ~ "!"; } say hello('David', 'Victor'); # Hello, David, Victor! sub hello($name is rw) { "Hello, " ~ ($name = $name.uc) ~ "!"; } my $mario = 'Mario'; say hello($mario); # Hello, MARIO! say $mario; # MARIO -
31/73 Anonymous Subroutines • Anonymous subroutine: • Pointy block (lambda)
syntax: my &hello = -> $name { "Hello, $name!" }; say &hello('Pablo'); # Hello, Pablo! my &hello = sub ($name) { "Hello, $name!" }; say &hello('Pablo'); # Hello, Pablo! say hello('Pablo'); # Hello, Pablo! .say for map(-> $name { "Hello, $name!" }, 'Raph', 'Pete'); # Hello, Raph! # Hello, Pete! -
32/73 Multiple Dispatch Subroutines • Same name, different signatures •
Example: multi hello(Str $name) { "Hello, $name!"; } multi hello(Numeric $number) { "Hello, number $number!"; } say hello('Angie'); # Hello, Angie! say hello(123); # Hello, number 123! -
34/73 Classes and Objects • At its core, Perl 6
is object oriented • But, it doesn't impose the object oriented programming style • Perl 6's object system design was an inspiration for Moose, the popular Perl 5 object framework -
35/73 Classes and Objects class Animal { has $species; #
Implicit private has $!gender; # Explicit private has $.age; # Accessor has $.name is rw; # Read/write } my $moose = Animal.new( species => 'Alces alces', gender => 'male', age => 12, ); say $moose.age; $moose.name = 'Edward'; -
36/73 Classes and Objects class Item { has ($.name, $.price);
} class ShoppingCart { has (@!items, $.total_price); method add_item(Item $item) { @!items.push($item); # Update a private attr $!total_price += $item.price; } } my $cart = ShoppingCart.new; $cart.add_item(Item.new(name => 'Beer', price => 3.50)); $cart.add_item(Item.new(name => 'Ketchup', price => 4.99)); say $cart.total_price; # 8.49 -
37/73 Classes and Objects class Item { has ($.name, $.price);
} class ShoppingCart { has (@!items, $.total_price); method add_item(Item $item) { @!items.push($item); $!total_price += self!price_after_tax($item.price); } # Private method method !price_after_tax($price) { $price * 1.23 } } -
38/73 Classes and Objects • Inherited class, using a role:
role Talking { method introduce { say 'Hello, my name is ' ~ self.name; } } class TalkingAnimal is Animal does Talking { } my $moose = TalkingAnimal.new( species => 'Alces alces', name => 'Frank' ); $moose.introduce; # Hello, my name is Frank -
39/73 Classes and Objects • Native types (like int or
bool) are boxed into objects • Methods can be called on them, like with regular objects: my int $n = 7; say $n.WHAT; # (Int) say $n.is-prime; # True -
41/73 Functional Programming • Perl 6 comes with many features
that facilitate functional programming • Like with object orientation, it's up to the programmer to make use of these features or not • (This is what this multi-paradigm thing is about) -
42/73 First-Class Functions • Functions/subroutines are first-class citizens • Can
be passed as arguments: • Can be returned by other functions: sub percentage($value) { return $value * 100 ~ '%'; } say map(&percentage, 0.1, 0.5, 1.5); # (10% 50% 150%) sub multiply($factor) { return sub ($value) { return $factor * $value }; } my &triple = multiply(3); say triple(9); # 27 -
43/73 Junctions • “Superpositions” of multiple values that can be
helpful for complex condition checking: if $code eq 'PL' || $code eq 'SE' || $code eq 'UK' { say "Sorry, payment in Euro not possible"; } if $code eq any('PL', 'SE', 'UK') { say "Sorry, payment in Euro not possible"; } if $code eq 'PL'|'SE'|'UK' { say "Sorry, payment in Euro not possible"; } -
44/73 Junctions • Other junctions – all (&): • one
(^): • none: my $password = 'Hunter1'; say 'Good' if $password ~~ all(/<[A..Z]>/, /<[0..9]>/); say 'Good' if $password ~~ /<[A..Z]>/ & /<[0..9]>/; my @values = (1 > 2, 3 == 4, 5 < 6); say 'Only one is true' if one(@values); my @numbers = (1, 0, 2, 5, 17); say 'No negative numbers' if none(@numbers) < 0; -
45/73 Feed Operator • Shows the flow of data more
clearly • So constructs like this: can be replaced with: or the other way around: @data ==> grep(* > 0) ==> unique() ==> sort() ==> @result; @result = sort(unique(grep(* > 0, @data))); @result <== sort() <== unique() <== grep(* > 0) <== @data; -
46/73 Method Chaining • Method calls can be chained •
Another feature that benefits code readability • So the construct shown earlier: can be written this way: @result = @data.grep(* > 0).unique.sort; @result = sort(unique(grep(* > 0, @data))); -
47/73 Meta Operators • Reduction meta operator ([?]) applies any
infix operator to all elements of a list: • Zip meta operator (Z?) applies an operator to successive pairs of items from two lists: my @numbers = (1, 2, 3, 4, 5); say "Sum: " ~ [+] @numbers; # Sum: 15 say "Product: " ~ [*] @numbers; # Product: 120 my @columns = <A B C>; my @rows = <1 2 3>; say @columns Z~ @rows; # (A1 B2 C3) -
48/73 Meta Operators • Cross meta operator (X?) applies any
infix operator to all pairs of items from two lists: • Reverse meta operator (R?) reverses the order of the arguments of an infix operator: my @columns = <A B C>; my @rows = <1 2 3>; say @columns X~ @rows; # (A1 A2 A3 B1 B2 B3 C1 C2 C3) say 5 - 3; # 2 say 5 R- 3; # -2 -
49/73 Meta Operators • Hyper operators (« and ») apply
an operator to one or two lists and return a list of results: • If one list is shorter, it can be auto-expanded: • Can also be used with unary operations: say (10,20,30,40,50) »+« (2,4,6,8,10); # (12 24 36 48 60) say (10,20,30,40,50) »+» (2,4,6); # (12 24 36 42 54) say -« (10,20,30,40,50); # (-10 -20 -30 -40 -50) -
51/73 Grammars • Grammars are regular expressions taken to the
next level • A grammar is composed of tokens and rules • Example – a simple arithmetic expression rule: my token number { \d+ } my token op { < + - * / > } my rule expression { <number> <op> <number> } say(('42 - 13' ~~ /<expression>/).Bool); # True -
52/73 Grammars my @s; grammar RPN { rule TOP {
<expression>+ } rule expression { <number> { @s.push($/<number>); } | <op> { @s.push(@s.pop + @s.pop) if $/<op> eq '+'; @s.push(@s.pop * @s.pop) if $/<op> eq '*'; } } token op { < + * > } token number { \d+ } } RPN.parse(@*ARGS.shift); # '2 3 + 4 *' say @s[0]; # 20 -
54/73 Concurrency et al. • The language is designed to
support concurrency and asynchronous programming • Built-in features include threads, promises, supplies, and channels • This allows for reactive and event-driven programming in Perl 6 -
55/73 Data Parallelism • The race and hyper methods iterate
over data structures in parallel • So the grep line in this fragment of code: can be replaced with either of these: my @numbers = (1..100000); my @primes = @numbers.grep(*.is-prime); @primes = @numbers.hyper.grep(*.is-prime); @primes = @numbers.race.grep(*.is-prime); -
56/73 Data Parallelism • The difference is that hyper preserves
the order of elements, while race does not • The batch size and degree of parallelism (i.e., the number of workers) can be set explicitly: @numbers.race(batch => 32, degree => 4).grep(*.is-prime); -
57/73 Promises • For asynchronously executing code and waiting for
results • Implemented by means of the Promise class: my $promise = Promise.new; say $promise.status; # Planned $promise.keep('As promised'); say $promise.status; # Kept say $promise.result; # As promised -
58/73 Promises • Starting a promise with a piece of
code and awaiting its result: my @numbers = 1..100000; my $promise = start grep *.is-prime, @numbers; say "Doing something else"; my @primes = await $promise; say @primes.elems; # 9592 -
60/73 Unicode Support • As seen with the hyper operators
(« and ») , Perl 6 embraces the use of Unicode in program code • Unicode characters can be used in identifiers • π, τ are built-in terms in Perl 6: sub circumference(Numeric $r) { τ * $r } -
61/73 Unicode Support • Unicode character as a subroutine name:
• Unicode data support is exceptionally good: sub Σ(*@elements) { [+] @elements } say Σ(1, 2, 3); # 6 say 'α'.succ; # β say 'Viel Spaß!'.uc; # VIEL SPASS! say 'Yes' if 'foobar' ~~ /foo.bar/; # Yes -
63/73 Modules • There's no Perl 6 equivalent of Perl's
glorious CPAN (yet) • A list of existing modules (mostly hosted on GitHub) is published at https://modules.perl6.org/ • Can be installed with the Panda utility (https://github.com/tadzik/panda/) -
64/73 Modules • The Inline::Perl5 module allows using many Perl
5 modules in Perl 6 programs • Even complex modules, such as DBI (database access interface), work • Usage is as simple as: use Inline::Perl5; use DBI:from<Perl5>; say DBI.available_drivers; # [DBM ExampleP File ... -
66/73 Oneliners • Print all lines of a text file
that exceed 80 characters: • Print a sum of comma-separated numbers • Fibonacci sequence (first n=10 elements): $ perl6 -e 'say((1, 1, * + * ... *)[^@*ARGS[0]])' 10 $ perl6 -ne '.print if .chars > 80' filename $ echo '1,2,3.14,4,0' | perl6 -ne 'say [+] .split(",")' $ perl6 -ne '.print if .chars > 80' filename $ perl6 -ne '.print if .chars > 80' filename -
68/73 But Wait! There's More! • This presentation only shows
some of all the interesting features of Perl 6 • (15 years is a long time, after all) • So go forth and explore! -
69/73 Sources and Resources • Perl 6 Home Site (http://perl6.org/)
• Perl 6 Docs (https://doc.perl6.org/) • Perl 6 Design Documents (http://design.perl6.org/) • Perl 6 Introduction (http://perl6intro.com/) • Perl 6 Advent Calendar (https://perl6advent.wordpress.com/) -
71/73 Want to Take Perl 6 for a Spin? •
Your best (easiest) option is Rakudobrew • Similar to what Perlbrew is for Perl 5, and virtualenv for Python • Installation is as simple as: git clone https://github.com/tadzik/rakudobrew ~/.rakudobrew export PATH=~/.rakudobrew/bin:$PATH rakudobrew init