Raku for Beginners: a hands-on tutorial
(A small introduction to a big language)
The Perl and Raku Conference
2022-06-22
Slide 2
Slide 2 text
Raku for Beginners
PLEASE DOWNLOAD THESE SLIDES!
http://speakerdeck.com/util
<<<
>>>
>>>
<<<
Slide 3
Slide 3 text
Preface
Slide 4
Slide 4 text
Preface
(This is the beginning of the Song...)
Slide 5
Slide 5 text
Raku for Beginners: a hands-on tutorial
(A small introduction to a big language)
The Perl and Raku Conference
2022-06-22
Slide 6
Slide 6 text
Raku for Beginners: a hands-on tutorial
(A small introduction to a big language)
The Perl and Raku Conference
2022-06-22
Slide 7
Slide 7 text
Raku for Beginners: a hands-on tutorial
(A small introduction to a big language)
The Perl and Raku Conference
2022-06-22
Slide 8
Slide 8 text
pruh-nuhn-see-ey-shuhn
[ rah-koo ]
/ ˈrɑ ku /
[ rey-koo ]
/ ˈreɪ ku /
!8
Slide 9
Slide 9 text
Bruce Gray (Util)
Slide 10
Slide 10 text
Jonathan Worthington (jnthn) Patrick Michaud (Pm)
Slide 11
Slide 11 text
No content
Slide 12
Slide 12 text
About the course
∞
NOT FOUND
Discussion encouraged!
Questions encouraged!
!12
Slide 13
Slide 13 text
Hands on: Try It And See
# From https://rakudo.org/star
# or https://rakudo.org/downloads
$ raku
Welcome to Rakudo™ v2022.04.
Implementing the Raku® Programming Language v6.d.
Built on MoarVM version 2022.04.
To exit type 'exit' or '^D'
[0] > say 42;
42
!13
Slide 14
Slide 14 text
!14
•https://glot.io/new/raku
•Docker:
•REPL on any system:
•docker run --rm -it rakudo-star
•Script on Mac or Unix:
• docker run --rm -v "$(pwd):/script" rakudo-star raku /script/a.raku
•Script on Windows:
• docker run --rm -v "%cd%:/script" rakudo-star raku /script/a.raku
REPL alternatives
Values know their type
> say 1.WHAT;
(Int)
> say 0.25.WHAT;
(Rat)
> say 1.23e4.WHAT;
(Num)
!20
Slide 21
Slide 21 text
Basic calculations
say 35 + 7; # 42
say 1.2 - 0.3; # 0.9
say 2.1e5 * 3.3e2; # 69300000
say 168 / 4; # 42
say 169 % 4; # 1
say 3 ** 3; # 27
!21
Slide 22
Slide 22 text
!22
• How big can integers get?
(Hint: try raising to a large power!)
• What type do you get when you divide
two integers?
• Try 0.1 + 0.2 == 0.3 in some other
language, then try it in Raku. What
do you observe?
Try it and see!
Improved calculations
say (6 % 3) == 0 # True
say 6 %% 3; # True
say 7 %% 3; # False
say 8 %% 3; # False
!31
Slide 32
Slide 32 text
Improved calculations
say (6 % 3) == 0 # True
say 6 %% 3; # True
say 7 %% 3; # False
say 8 %% 3; # False
say (8 / 3).Int # 2
!32
Slide 33
Slide 33 text
Improved calculations
say (6 % 3) == 0 # True
say 6 %% 3; # True
say 7 %% 3; # False
say 8 %% 3; # False
say (8 / 3).Int # 2
say 8 div 3; # 2
!33
Slide 34
Slide 34 text
Numeric routines
ceiling floor truncate round
abs sign sqrt
exp log log10 log2
sin sinh asin asinh
cos cosh acos acosh
tan tanh atan atanh atan2
sec sech asec asech
cosec cosech acosec acosech
cotan cotanh acotan acotanh
cis polar unpolar roots conj
!34
Slide 35
Slide 35 text
Strings
say 'Gangnam style!';
say "Much wow!";
!35
Slide 36
Slide 36 text
Strings
say 'Gangnam style!';
say "Much wow!";
say 'Me\t&\tBobby McGee';
Me\t&\tBobby McGee
say "Me\t&\tBobby McGee";
Me & Bobby McGee
!36
Slide 37
Slide 37 text
Stitching strings together
String concatenation operator:
~
say 'in' ~ 'finite';
# infinite
!37
Slide 38
Slide 38 text
!38
•What happens if you forget about
the tilde `~`, and instead try to
use the dot `.` to concatenate two
strings?
•What happens if you completely
forget to put an operator between
the two strings?
Think-o: Try it and see!
Slide 39
Slide 39 text
Awesome error messages!
> say "a" . "b";
===SORRY!=== Error while compiling:
Unsupported use of . to concatenate strings.
In Raku please use: ~.
------> say "a" .⏏ "b";
!39
Slide 40
Slide 40 text
Awesome error messages!
> say "a" "b";
===SORRY!=== Error while compiling:
Two terms in a row
------> say "a"⏏ "b";
expecting any of:
infix
infix stopper
postfix
statement end
statement modifier
statement modifier loop
!40
Slide 41
Slide 41 text
Some common string operations
say uc('nyanCat'); # NYANCAT
say lc('nyanCat'); # nyancat
say tclc('nyanCat'); # Nyancat
say substr('nyanCat', 2, 3); # anC
say chars('nyanCat'); # 7
!41
Slide 42
Slide 42 text
Some common string operations
say uc 'nyanCat'; # NYANCAT
say lc 'nyanCat'; # nyancat
say tclc 'nyanCat'; # Nyancat
say substr 'nyanCat', 2, 3; # anC
say chars 'nyanCat'; # 7
!42
Slide 43
Slide 43 text
Some common string operations
say 'nyanCat'.uc; # NYANCAT
say 'nyanCat'.lc; # nyancat
say 'nyanCat'.tclc; # Nyancat
say 'nyanCat'.substr(2, 3); # anC
say 'nyanCat'.chars; # 7
!43
Slide 44
Slide 44 text
Burned dessert
Brûlée
!44
Slide 45
Slide 45 text
!45
• Graphemes: Things that a human would think
of as "a character"
• Codepoints: Things Unicode gives a number
to (letters, numbers, marks, diacritics,
symbols)
• Bytes: The way codepoints are represented on
disk, on the wire, etc.
What does .chars really tell you?
Slide 46
Slide 46 text
!46
• Graphemes: Things that a human would think
of as "a character"
What does .chars really tell you?
Slide 47
Slide 47 text
Dessert dissected
Brûlée
B r û l é e
!47
Slide 48
Slide 48 text
Dessert dissected
Brûlée
B r û l é e
42 72 c3bb 6c c3a9 65
!48
Slide 49
Slide 49 text
Booleans
Raku provides True and False values of type Bool.
say False.WHAT; # (Bool)
say True.WHAT; # (Bool)
All types know how to "boolify" themselves. You can ask them to
with the `?` operator, or `!` to also negate that boolification.
say ?42; # True
say ?0; # False
say !0; # True
say so 0; # False ( lower precedence form of ? )
say not 0; # True ( lower precedence form of ! )
!49
Slide 50
Slide 50 text
Coercions
? so Force to Boolean
! not Force to Boolean and negate
+ Force to Numeric
- Force to Numeric and negate
~ Force to String
!50
Slide 51
Slide 51 text
Coercions
Numifying a string that does not contain a valid number
gives a `Failure` (a lazy exception, which is thrown if the value
is used, but can be "defused" by testing it; more later!)
> say +' 5 ';
5
> say +' 5 Wow!';
Cannot convert string to number:
trailing characters after number
in ' 5⏏ Wow!' (indicated by ⏏)
!51
Slide 52
Slide 52 text
!52
• What string values are True and False?
• ?''
• ?'0'
• ?'False'
• What types do you get for these?
(Hint: be careful with precedence;
.WHAT binds tighter than a prefix operator.)
• +'42'
• +'1.5'
• +'4.2e4'
• What do True and False numify to?
Coercions: Try it and see!
Scalars hold a single item
$answer = 42;
===SORRY!=== Error while compiling:
Variable '$answer' is not declared
------> ⏏$answer = 42;
!64
Slide 65
Slide 65 text
Scalars hold a single item
my $answer;
$answer = 42;
!65
Slide 66
Slide 66 text
Scalars hold a single item
my $answer;
$answer = 42;
say $answer; # 42
!66
Slide 67
Slide 67 text
Scalars hold a single item
my $answer;
$answer = 42;
say $answer; # 42
$answer = $answer - 5;
!67
Slide 68
Slide 68 text
Scalars hold a single item
my $answer;
$answer = 42;
say $answer; # 42
$answer = $answer - 5;
!68
Slide 69
Slide 69 text
Scalars hold a single item
my $answer;
$answer = 42;
say $answer; # 42
$answer = $answer - 5;
$answer -= 5;
!69
Slide 70
Slide 70 text
Scalars hold a single item
my $answer;
$answer = 42;
say $answer; # 42
$answer = $answer - 5;
$answer -= 5;
say $answer; # 37
!70
Slide 71
Slide 71 text
Vars untyped unless specified
my $answer;
$answer = 42;
say $answer; # 42
$answer = $answer - 5;
$answer -= 5;
say $answer; # 37
my $age = "I'm thirty seven -- I'm not old!";
!71
Slide 72
Slide 72 text
Typed Vars
my Int $speed = 125;
my Str $singer = 'Hagar';
!72
Slide 73
Slide 73 text
Typed Vars
my Int $speed = 125;
my Str $singer = 'Hagar';
$speed /= 2;
!73
Slide 74
Slide 74 text
!74
• What happens if you declare a variable
with a type, like `my Int $age;`, then
try to assign it a value of a different
type?
• What is the value in a variable that has
been declared but not initialized?
(Hint: use .raku method to look)
• Same question, but the variable was
declared with a type.
Typed vars: Try it and see
Slide 75
Slide 75 text
Typed Vars
my Int $speed = 125;
my Str $singer = 'Hagar';
$speed /= 2;
Type check failed in assignment to
$speed; expected Int but got Rat
(62.5)
!75
Slide 76
Slide 76 text
Typed Vars
my Numeric $speed = 125;
my Str $singer = 'Hagar';
$speed /= 2; # is now 62.5
!76
Slide 77
Slide 77 text
Scalars: Behind the
Scenes
(skipped!)
Slide 78
Slide 78 text
Arrays
my @countries;
!78
Slide 79
Slide 79 text
Arrays
my @countries =
'UK', 'Peru', 'Spain', 'Sweden';
!79
Slide 80
Slide 80 text
Arrays
my @countries =
'UK', 'Peru', 'Spain', 'Sweden';
say @countries.WHAT; # (Array)
say @countries.elems; # 4
!80
Slide 81
Slide 81 text
Array indexing
my @countries =
'UK', 'Peru', 'Spain', 'Sweden';
say @countries[0]; # UK
say @countries[*-1]; # Sweden
!81
Slide 82
Slide 82 text
Array indexing
my @countries =
'UK', 'Peru', 'Spain', 'Sweden';
@countries[4] = 'Czech Republic';
say @countries.elems; # 5
!82
Slide 83
Slide 83 text
Array indexing
my @countries =
'UK', 'Peru', 'Spain', 'Sweden';
@countries[1, 2] = @countries[2, 1];
say @countries[0, 1, 2];
# UK Spain Peru
say @countries[0..2];
!83
Slide 84
Slide 84 text
Arrays and binding
When you assign into an array, each element is a
`Scalar` container. You can therefore bind array
elements.
my $first := @countries[0];
$first = 'England';
say @countries[0]; # England
Again, you probably won't do this much yourself.
However, it is the mechanism that is behind things
like:
@values[$idx]++;
!84
Slide 85
Slide 85 text
Quote words
my @countries =
'UK', 'Peru', 'Spain', 'Sweden';
!85
Slide 86
Slide 86 text
Quote words
my @countries =
'UK', 'Peru', 'Spain', 'Sweden';
my @countries = ;
!86
Slide 87
Slide 87 text
Quote words
my @countries =
'UK', 'Peru', 'Spain', 'Sweden';
my @countries = ;
my @countries = < United Kingdom Peru Spain Sweden >;
!87
Slide 88
Slide 88 text
Quote words
my @countries =
'UK', 'Peru', 'Spain', 'Sweden';
my @countries = ;
my @countries = << 'United Kingdom' Peru Spain Sweden >>;
!88
Slide 89
Slide 89 text
Quote words
my @countries =
'UK', 'Peru', 'Spain', 'Sweden';
my @countries = ;
my @countries = << 'United Kingdom' Peru Spain Sweden >>;
my @countries = « 'United Kingdom' Peru Spain Sweden »;
!89
Slide 90
Slide 90 text
Stack/queue behavior
You can `push`/`pop` at the end of an array:
my @values;
@values.push(35);
@values.push(7);
@values.push(@values.pop + @values.pop);
We could have used the `push`/`pop` functions also.
At the start of an array, we can use `unshift` and
`shift`. Using `push` and `shift` in combination,
you get queue semantics.
!90
Slide 91
Slide 91 text
Stack/queue behavior
!91
0 1 2 3 4
Ariel Belle Cinderella Dumbo Eeyore
shift
unshift
push
pop
Slide 92
Slide 92 text
Stack of Disney
my @disney =
;
@disney.push(@disney.pop ~ @disney.pop);
!92
0 1 2 3 4
Ariel Belle Cinderella Dumbo Eeyore
shift
unshift
push
pop
Slide 93
Slide 93 text
!93
• What happens if you assign to slot 0 and 3 of an array?
What is `.elems`, and what do the slots 1 and 2
contain?
• If you assign one array to another, do you get a fresh set
of scalars?
• What happens if you bind an array to another array?
• What happens if you bind a quote-words list directly to
an `@variable`? Can you assign to its elements?
Arrays: Try it and see!
Slide 94
Slide 94 text
@array %hash
Positional Associative
Slide 95
Slide 95 text
COBOL SNOBOL
Slide 96
Slide 96 text
Hashes
my %capitals;
!96
Slide 97
Slide 97 text
Hashes
my %capitals;
!97
Slide 98
Slide 98 text
Hashes
my %capitals;
my %capitals = ;
!98
Slide 99
Slide 99 text
Hashes
my %capitals;
my %capitals = ;
my %capitals =
UK => 'London',
Peru => 'Lima',
;
!99
Pair
ABC => 'XYZ'
> say ( ABC => 'XYZ' ).WHAT;
(Pair)
> say ( ABC => 'XYZ' ).key;
ABC
> say ( ABC => 'XYZ' ).value;
!108
Slide 109
Slide 109 text
Pair
ABC => 'XYZ'
> say ( ABC => 'XYZ' ).WHAT;
(Pair)
> say ( ABC => 'XYZ' ).key;
ABC
> say ( ABC => 'XYZ' ).value;
XYZ
!109
Slide 110
Slide 110 text
Pair
> my $p = ABC => 'XYZ';
> say $p.WHAT; # (Pair)
> say $p.key; # ABC
> say $p.value; # XYZ
!110
Slide 111
Slide 111 text
Hashes
my %capitals;
my %capitals = ;
my %capitals =
UK => 'London',
Peru => 'Lima',
;
!111
Slide 112
Slide 112 text
Hashes
my %capitals =
UK => 'London',
Peru => 'Lima',
;
!112
Slide 113
Slide 113 text
Hashes
my %capitals = UK => 'London',
Peru => 'Lima';
.
!113
Slide 114
Slide 114 text
Indexing and slicing
my %capitals = UK => 'London',
Peru => 'Lima';
say %capitals{'UK'}; # London
a
!114
Slide 115
Slide 115 text
Indexing and slicing
my %capitals = UK => 'London',
Peru => 'Lima';
say %capitals{'UK'}; # London
say %capitals{'UK', 'Peru'}; # London Lima
!115
Slide 116
Slide 116 text
Indexing and slicing
my %capitals = UK => 'London',
Peru => 'Lima';
say %capitals{'UK'}; # London
say %capitals{'UK', 'Peru'}; # London Lima
!116
Slide 117
Slide 117 text
Indexing and slicing
my %capitals = UK => 'London',
Peru => 'Lima';
say %capitals{'UK'}; # London
say %capitals{'UK', 'Peru'}; # London Lima
say %capitals;
say %capitals;
!117
Slide 118
Slide 118 text
Indexing and slicing
my %capitals = UK => 'London',
Peru => 'Lima';
say %capitals{'UK'}; # London
say %capitals{'UK', 'Peru'}; # London Lima
say %capitals;
say %capitals;
say %capitals{$country};
!118
Slide 119
Slide 119 text
Existence and deletion
There is no `exists` function or method in Raku.
Instead, you use the normal indexing syntax and add
the `:exists` adverb:
> say %capitals:exists;
True
> say %capitals:exists;
False
> say %capitals:exists;
(True True False)
!119
Slide 120
Slide 120 text
Existence and deletion
The same goes for deletion:
%capitals = %capitals;
%capitals = 'Edinburgh';
%capitals:delete;
!120
Slide 121
Slide 121 text
Other useful Hash methods
my %capitals = UK => 'London', Peru => 'Lima';
say %capitals.keys; # (Peru UK)
say %capitals.values;# (Lima London)
say %capitals.pairs; # (Peru => Lima UK => London)
say %capitals.kv; # (Peru Lima UK London)
!121
Slide 122
Slide 122 text
!122
• Are pairs first-class objects in Raku?
Hint: (UK => 'London').WHAT
• Suppose you declare the hash in our examples, and have
`my $a = 'UK';`. Think about what `%capitals{$a}` will do
compared to `%capitals<$a>`.
Try it and see if you guessed correctly!
• What happens if you assign one hash to another?
What if you assign a hash to an array?
How about an array to a hash?
• What happens if you use any of these on an array?
.keys .values .kv .pairs
Pairs & Hashes: Try it and see!
BTW: Constants
# Perl 5:
use constant E => exp(1);
use constant PI => 4 * atan2(1, 1);
use constant TAU => 2 * atan2(0,-1);
!124
Slide 125
Slide 125 text
BTW: Constants
# Perl 5:
use constant E => exp(1);
use constant PI => 4 * atan2(1, 1);
use constant TAU => 2 * atan2(0,-1);
# Raku:
𝑒 e
π pi
τ tau
!125
Slide 126
Slide 126 text
Interpolation basics
There are numerous advantages to variables having
sigils. One of them is easy **interpolation** of
variables in strings.
First off, **single quoted** strings do not interpolate:
my $who = 'your mom';
say '$who ate the pie'; # $who ate the pie
In double-quoted strings, strings interpolate pretty
much as you'd expect:
say "$who ate the pie"; # your mom ate the pie
!126
Slide 127
Slide 127 text
Interpolation of arrays and hashes
It's possible to interpolate arrays and hashes, but you need
to make a little more effort than with scalars. That way, we
don't mangle email addresses.
say "Contact [email protected]"; # Contact [email protected]
Instead, you need to index. Note that the empty index, known
as the **zen slice**, allows you to get all elements.
my @winners = ;
say "The winner is @winners[0]";
say "Top 3 were @winners[]";
The same rules apply for hashes.
!127
Slide 128
Slide 128 text
Interpolating method calls
You can also interpolate method calls on any kind
of variable:
my @winners = ;
say "Top 3 are: @winners.join(', ')";
say "CONGRATULATIONS @winners[0].uc()!";
Note that this will not happen if you don't put the
parentheses on, so we will not screw up things
involving file extensions:
my $fh = open "$file.txt"; # Does not try
and call .txt
!128
Slide 129
Slide 129 text
Try it and see
* You can embed code inside an
interpolated string using curlies `{ … }`.
Try doing a calculation inside of one;
summing $x and $y .
* `"$name"` is the one common
gotcha from the Raku interpolation rules.
What happens if you try it?
Why does it happen?
Can you find a solution?
!129
Slide 130
Slide 130 text
Very Basic I/O
Slide 131
Slide 131 text
The standard handles
Use `say` to write a line to standard output,
and `note` to write a line to standard error.
say "it again";
note "Uh-oh…";
A convenient way to write out a prompt and
read a line from standard input is the
`prompt` function:
my $color = prompt "Name a color: ";
!131
Slide 132
Slide 132 text
Working with files
We can read a file entirely into a scalar using
`slurp`, or into an array of lines by getting an IO
handle and calling `lines`:
my $whole-file = slurp $filename;
my @lines = $filename.IO.lines;
The opposite of `slurp` is `spurt`:
spurt $filename, $stuff;
Naturally, you can do much more than this - but
it's enough for now.
!132
Slide 133
Slide 133 text
> say .raku for 'a.dat'.IO.slurp;
"abc\ndef\n"
> say .raku for 'a.dat'.IO.lines;
"abc"
"def"
!133
Slide 134
Slide 134 text
Flow control
Slide 135
Slide 135 text
Comparisons
Numeric String
Equal == eq
Not equal != ne
Less than < lt
Less than or equal <= le
Greater than > gt
Greater than or equal >= ge
!135
Slide 136
Slide 136 text
Aside: general design rule
Perl has generally followed the view that different semantics
means different operator. This means that you know how the
program will behave even if you don't know the exact types of
the data.
There's no question that `==` means numeric equality and `eq`
means string equality, or that `+` is addition and `~` is
concatenation.
In Raku we've de-confused a few things from Perl 5.
say 'edam'.flip; # made
say (1, 2, 3).reverse; # 3 2 1
say 'omg' x 2; # (string 'omgomg')
say 'omg' xx 2; # (a list containing 'omg' twice)
!136
Slide 137
Slide 137 text
if, elsif, else
my $num = prompt 'Enter a number: ';
if $num < 0 {
say 'Negative';
}
elsif $num > 0 {
say 'Positive';
}
else {
say 'Zero';
}
!137
if, elsif, else
my $num = prompt 'Enter a number: ';
my $s = $num < 0 ?? 'Negative'
!! $num > 0 ?? 'Positive'
!! 'Zero';
say $s;
!139
Slide 140
Slide 140 text
if, elsif, else
my $num = prompt 'Enter a number: ';
say $num < 0 ?? 'Negative'
!! $num > 0 ?? 'Positive'
!! 'Zero';
!140
Slide 141
Slide 141 text
if, elsif, else
my $num = prompt 'Enter a number: ';
say [1 + ($num <=> 0)];
!141
Slide 142
Slide 142 text
Postfix If
shout() if you_need_something();
$a = 5 if $b > 12;
say "It's alive!" unless $it-is-not-alive;
warn "Printer on fire?" unless $printer_printed;
!142
Slide 143
Slide 143 text
If, with pointy blocks
my $name = get-user-name($user-id);
if $name {
…
}
!143
Slide 144
Slide 144 text
If, with pointy blocks
my $name = get-user-name($user-id);
if $name {
…
}
…
…
…
…
…
…
…
…
!144
Slide 145
Slide 145 text
If, with pointy blocks
my $name = get-user-name($user-id);
if $name {
…
}
if ( my $name = get-user-name($user-id) ) {
…
}
!145
Slide 146
Slide 146 text
If, with pointy blocks
my $name = get-user-name($user-id);
if $name {
…
}
if ( my $name = get-user-name($user-id) ) {
…
}
if get-user-name($user-id) -> $name {
…
}
!146
Slide 147
Slide 147 text
If, with pointy blocks
my $name = get-user-name($user-id);
if $name {
…
}
if ( my $name = get-user-name($user-id) ) {
…
}
if get-user-name($user-id) -> my $name {
…
}
!147
Slide 148
Slide 148 text
If, with pointy blocks
my $name = get-user-name($user-id);
if $name {
…
}
if ( my $name = get-user-name($user-id) ) {
…
}
if get-user-name($user-id) -> Str $name {
…
}
!148
Slide 149
Slide 149 text
given/when
given prompt 'Enter a number: ' {
when * < 0 {
say 'Negative';
}
when * > 0 {
say 'Positive';
}
default {
say 'Zero';
}
}
!149
Slide 150
Slide 150 text
Loops: loop
The `loop` statement is for writing an infinite loop.
loop {
print 'OVER HANG';
}
!150
Slide 151
Slide 151 text
The good old days
10 PRINT "HIT BULLS"
20 GOTO 10
!151
Slide 152
Slide 152 text
Loops: loop
The `loop` statement is for writing an infinite loop.
loop {
print 'OVER HANG';
}
You can also use it for C-style loops:
loop ( my $i = 10 ; $i > 0 ; $i-- ) {
print $i, ' ';
}
say 'LIFT OFF!';
!152
Slide 153
Slide 153 text
Loops: while/until
The `while` loop is rather unsurprising:
my @tasks;
while @tasks.elems < 5 {
@tasks.push( prompt('Enter a task: ') );
}
Sometimes, `until` is more natural:
my @tasks;
until @tasks.elems >= 5 {
@tasks.push( prompt('Enter a task: ') );
}
!153
Slide 154
Slide 154 text
Loops: while/until with pointy blocks
We can also test a value for truth and capture it into a variable only
visible inside the block loop:
my @tasks;
while prompt('Enter a task (blank if done): ') -> $t {
@tasks.push($t);
}
!154
Slide 155
Slide 155 text
Loops: while/until with pointy blocks
my @tasks;
constant $request_task =
'Enter a task (blank if done): ';
while prompt($request_task) -> $t {
@tasks.push($t);
}
!155
Slide 156
Slide 156 text
Try it and see!
Write the classic "guess my number" game. Pick a
random number between 1 and 100 (hint: `my $number =
(1..100).pick`). Let the user make up to 7 guesses.
If they get it right, say they won and `exit;`. If
not, state they are too high or too low. If they
don't get it in 7 guesses, tell them they suck.
If you finish this, investigate using `last` instead
of `exit`. After this refactor, try to implement
giving the option to play again "yes/no". If you're
still way ahead, make it multi-player, reading in
two player names and letting them take turns.
!156
Slide 157
Slide 157 text
Iteration
for @tasks -> $task {
say $task.tclc;
}
!157
Slide 158
Slide 158 text
Iteration
for @tasks -> $task is rw {
say $task.tclc;
}
!158
Slide 159
Slide 159 text
Iteration
for @tasks -> $task is rw {
say $task.tclc;
}
for @tasks <-> $task {
say $task.tclc;
}
!159
Slide 160
Slide 160 text
Iteration
for @tasks {
say .tclc;
}
!160
Slide 161
Slide 161 text
Iteration
for @tasks { # uses topic $_
say .tclc;
}
!161
Slide 162
Slide 162 text
Iteration
for @tasks {
say .tclc;
}
say .tclc for @tasks;
!162
Slide 163
Slide 163 text
Loops: loop
The `loop` statement is for writing an infinite loop.
loop {
print 'OVER HANG';
}
You can also use it for C-style loops:
loop ( my $i = 10 ; $i > 0 ; $i-- ) {
print $i, ' ';
}
say 'LIFT OFF!';
!163
!184
• What do you expect this code to do?
for ^8 -> $a {
say $a;
}
Try it!
• What if you edit both occurrences of `$a` in the
code, typing `$a, $b` in place of `$a`?
• Same question, but `$a, $b, $c` !
You-pick-two: Try it and see!
Slide 185
Slide 185 text
REPL'ed: N-at-a-time
> for ^8 -> $a { say $a }
0
1
2
3
4
5
6
7
> for ^8 -> $a, $b { say $a, $b }
01
23
45
67
!185
Slide 186
Slide 186 text
REPL'ed: N-at-a-time
> for ^8 -> $a, $b, $c { say $a, $b, $c }
012
345
Too few positionals passed; expected 3 arguments but got 2
in block at line 1
> for ^8 -> $a, $b, $c? { say $a, $b, $c }
012
345
67(Mu)
!186
Slide 187
Slide 187 text
TPRC Bonus!
use 5.36.0;
use experimental qw;
for my ($x, $y) ('A'..'F') {
say $x, $y;
}
!187
Slide 188
Slide 188 text
https://rjbs.cloud/blog/2022/05/perl-5.36/
use 5.36.0;
use experimental qw;
for my ($x, $y) ('A'..'F') {
say $x, $y;
}
AB
CD
EF
!188
Slide 189
Slide 189 text
REPL'ed: N-at-a-time
> for ^8 -> $a, $b, $c { say $a, $b, $c }
012
345
Too few positionals passed; expected 3 arguments but got 2
in block at line 1
> for ^8 -> $a, $b, $c? { say $a, $b, $c }
012
345
67(Mu)
!189
Slide 190
Slide 190 text
.kv
Slide 191
Slide 191 text
Lists have Keys, too!
for .kv -> $num, $name {
say "$num. $name";
}
!191
Slide 192
Slide 192 text
Sarah is Number One!
for .kv -> $num, $name {
say "$num. $name";
}
0. Bruce
1. Sarah
!192
Slide 193
Slide 193 text
Zer0 , from Borderlands 2
for .kv -> $num, $name {
say "$num. $name";
}
0. Bruce
1. Sarah
!193
Slide 194
Slide 194 text
Hash.kv
my %capitals =
UK => 'London', Peru => 'Lima';
for %capitals.kv -> $country, $city {
say "$city is the capital of $country";
say "$city's capital is $country";
say "{$city}'s capital is $country";
}
!194
Slide 195
Slide 195 text
Not just for .kv
You can take two (or three, or more) at a time from any
array, not just with `.kv`. For example, suppose we
wanted to shuffle and randomly pair up people to dance
together, we could do:
my @dancers = ;
for @dancers.pick(*) -> $first, $second {
say "$first dances with $second";
}
Note that this will fail if there are an odd number of
dancers. Soon, we'll discover that the pointy block
arguments are just a special case of Raku signatures,
and you can make one optional or set a default.
!195
Slide 196
Slide 196 text
!196
• 5..8 + 12
•(5..8) + 12
•(5..8) * 3
•(5..8) / 12
•(5..8) + (8..9)
Back to Ranges: Try it and See!
Slide 197
Slide 197 text
Try it and see!
Create a file with various words in. Loop over
the words with a `for` loop (hint: you can put
one word per line in the file and use
`lines('file'.IO)`).
Use a hash to count how many times you've seen
each word (use the `++` increment operator).
Then loop over the hash to show how many times
each word was seen.
If you get done: make it case insensitive, and
implement some means to filter out very common
words ('a', 'the', 'is', etc').
!197
Slide 198
Slide 198 text
Subs and signatures
Slide 199
Slide 199 text
Subs and signatures
"Callable" code
Slide 200
Slide 200 text
Callable Code: Sub
sub dance_with ( $partner ) {
say "Dancing with $partner";
}
!200
Slide 201
Slide 201 text
Callable Code: Sub
sub dance_with ( $partner ) {
say "Dancing with $partner";
}
!201
Slide 202
Slide 202 text
Callable Code: Sub
sub dance_with ( $partner ) {
say "Dancing with $partner";
}
!202
Slide 203
Slide 203 text
Callable Code: Sub
sub dance_with ( $partner ) {
say "Dancing with $partner";
}
!203
Slide 204
Slide 204 text
Callable Code: Sub
sub dance_with ( $partner ) {
say "Dancing with $partner";
}
> dance_with('Sarah');
!204
Slide 205
Slide 205 text
Callable Code: Sub
sub dance_with ( $partner ) {
say "Dancing with $partner";
}
> dance_with('Sarah');
Dancing with Sarah
!205
Slide 206
Slide 206 text
Callable Code: Sub
sub dance_with ( $partner ) {
say "Dancing with $partner";
}
> dance_with('Sarah');
Dancing with Sarah
!206
Slide 207
Slide 207 text
Callable Code: Sub
sub dance_with ( $partner ) {
say "Dancing with $partner";
}
> dance_with('Sarah');
Dancing with Sarah
> dance_with('Sarah', 'Jill');
!207
Slide 208
Slide 208 text
Callable Code: Sub
sub dance_with ( $partner ) {
say "Dancing with $partner";
}
> dance_with('Sarah');
Dancing with Sarah
> dance_with('Sarah', 'Jill');
Calling dance_with(Str, Str) will never
work with declared signature ($partner)
!208
Slide 209
Slide 209 text
Callable Code: Sub
sub dance_with ( $partner ) {
say "Dancing with $partner";
}
> dance_with('Sarah');
Dancing with Sarah
> dance_with('Sarah', 'Jill');
Calling dance_with(Str, Str) will never
work with declared signature ($partner)
!209
Slide 210
Slide 210 text
Pointy blocks can go solo
We've already seen that "pointy blocks" can go on
`for`/`while` loops, `if` statements, and so forth.
However, writing one alone gives you a callable
piece of code. You can store it in a variable:
my $greeter = -> $greeting, $name { say
"$greeting, $name!" };
And later call it:
$greeter('Hej', 'Carl'); # Hej, Carl!
Of course, there's a more convenient way…
!210
Slide 211
Slide 211 text
Sub declarations
We can use the `sub` keyword to declare a subroutine:
sub truncate($text) {
$text.chars > 100
?? "$text.substr(0, 100)…"
!! $text
}
We can then call it in one of the following ways:
my $short = truncate($text); # Function call form
my $short = truncate $text; # List op form
!211
Slide 212
Slide 212 text
Syntax rules for calls
There are a couple of consistent rules about how calls are
parsed.
First, `foo(…)` is **always** a call. It even beats
keywords.
sub if($cond, $code) { if $cond { $code() } }
if(True, -> { say "Wow, a sub called 'if'!" });
Second, whitespace after the sub name will **always** make
it a list op. This
XXX code
say substr "craft", 1; # Correct, substr gets 2 args
say substr ("craft", 1); # WRONG, substr gets 1 arg (a list)
!212
Slide 213
Slide 213 text
Returning results
Our `truncate` sub worked fine because by default a sub returns the
value produced by its final statement. We could have been more
explicit by using `return`:
sub truncate($text) {
return $text.chars > 100
?? "$text.substr(0, 10)…"
!! $text
}
In this case, it's a matter of personal preference. However, in
other cases you may need `return` in order to return from a nested
block.
Note that **pointy blocks are transparent to `return`**. You can not
`return` out of a pointy block, only out of a routine (that is, a
`sub` or a `method`, which we'll see soon).
!213
Slide 214
Slide 214 text
Passing arrays and hashes
sub trim-to-shortest ( @a, @b ) {
pop @a while @a > @b;
pop @b while @b > @a;
}
my @x = 1..9;
my @y = 5..7;
trim-to-shortest(@x, @y);
say @x; # 1 2 3
say @y; # 5 6 7
!214
Slide 215
Slide 215 text
Passing arrays and hashes
sub trim-to-shortest ( @a, @b ) {
pop @a while @a > @b;
pop @b while @b > @a;
}
my @x = 1..9;
my @y = 5..7;
trim-to-shortest(@x, @y);
say [ :@x, :@y ].raku;
# [:x([1, 2, 3]), :y([5, 6, 7])]
!215
Slide 216
Slide 216 text
!216
• argument: thing you are passing when you
call a sub (or other code)
•
•
•
A note on terminology
Slide 217
Slide 217 text
!217
• argument: thing you are passing when you
call a sub (or other code)
• argument list: list of zero or more arguments
•
•
A note on terminology
Slide 218
Slide 218 text
!218
• argument: thing you are passing when you
call a sub (or other code)
• argument list: list of zero or more arguments
• Parameter: thing you declare that receives the
argument
•
A note on terminology
Slide 219
Slide 219 text
!219
• argument: thing you are passing when you
call a sub (or other code)
• argument list: list of zero or more arguments
• Parameter: thing you declare that receives the
argument
• Signature: list of zero or more Parameters
A note on terminology
Slide 220
Slide 220 text
!220
• argument: thing you are passing when you
call a sub (or other code)
• argument list: list of zero or more arguments
• Parameter: thing you declare that receives the
argument
• Signature: list of zero or more Parameters
A note on terminology
Slide 221
Slide 221 text
!221
• argument: thing you are passing when you
call a sub (or other code)
• argument list: list of zero or more arguments
• Parameter: thing you declare that receives the
argument
• Signature: list of zero or more Parameters
Petrified Lingo
Slide 222
Slide 222 text
Try it and see!
See how a couple of possible failure modes work
out:
* What happens if you call a sub with the wrong
number of arguments? Do you get an error? Is it
compile time or runtime?
* Make a typo when calling a sub. Do we find it
at compile time or runtime?
Next, refactor your word frequency program into
two subs: `calculate-frequencies` and `display-
frequencies`.
!222
Slide 223
Slide 223 text
Functional
Programming
(Higher-Order Raku)
Slide 224
Slide 224 text
grep
my @odds = grep { $_ !%% 2 }, 0..9;
!224
Slide 225
Slide 225 text
Optional parameters
When we put a `?` on a parameter, we make it optional.
If no argument is passed for it, then it will contain
`Any`. This "undefined" value is false in boolean
context, so we can do this:
XXX Move to API!!! No, needed for MAIN
my @dancers = ;
for @dancers.pick(*) -> $first, $second? {
if $second {
say "$first dances with $second";
}
else {
say "$first dances alone";
}
}
!225
Slide 226
Slide 226 text
Default values
Another way to make a parameter optional is to supply a
**default**:
my @dancers = ;
for @dancers.pick(*) -> $first, $second = 'the teacher' {
say "$first dances with $second";
}
Defaults are evaluated per call. Further, since we bind left
to right, it is possible to default to a previous parameter:
sub log-event($event, $occurred = now, $logged =
$occurred) {
# …
}
!226
Slide 227
Slide 227 text
Named arguments/parameters
It's also possible to use named arguments and parameters.
These are typically used for extra configuration and
options, and so they are **optional by default**.
sub truncate($text, :$limit = 100, :$trailer = '…') {
$text.chars > $limit
?? "$text.substr(0, $limit)$trailer"
!! $text
}
say truncate("Drink a beer", limit => 11); # Drink a bee…
!227
Slide 228
Slide 228 text
Other ways to pass named arguments
We have a number of different syntaxes for named arguments.
limit => 11 # fat arrow syntax
:limit(11) # colon pair syntax
The colon pair syntax has some special cases for booleans:
:global # same as :global(True)
:!global # same as :global(False)
And also one for passing on a variable with the same name
as the parameter:
:$global # same as :global($global)
!228
Slide 229
Slide 229 text
Slurpy parameters
Also we have slurpy parameters, when we want to accept
any number of arguments.
There are a few forms of these. For example, we can take
all positionals:
sub join-and-truncate($joiner, $limit, *@values) {
truncate(@values.join($joiner), limit => $limit);
}
Or perhaps also all the named arguments:
sub join-and-truncate($joiner, *@values, *%options) {
# … but how to pass the options on to truncate?
}
!229
Slide 230
Slide 230 text
Flattening arguments
The "opposite" of slurping is flattening an
array or hash into an argument list. This
is done with the `|` prefix operator (which
is only meaningful inside of an argument
list).
sub join-and-truncate($joiner,
*@values, *%options) {
truncate(@values.join($joiner), |
%options);
}
!230
Slide 231
Slide 231 text
Slurpy positionals and flattening
It's sometimes important to remember that `*@pos` will
flatten incoming arrays into a single array. Therefore, if
you want to write this:
sub check-array-lengths(*@arrays) {
for @arrays -> @arr {
die "Oh no it's too long!" if @arr.elems > 5;
}
}
my @a = 1..4;
my @b = 1..3;
check-array-lengths(@a, @b);
You'll end up in a mess, with `@arrays` containing 7 `Int`s!
!231
Slide 232
Slide 232 text
Non-flattening slurpy positional
You can prevent this steam-rollering by using
`**@arrays` instead:
sub check-array-lengths(*@arrays) {
for @arrays -> @arr {
die "Oh no it's too long!" if
@arr.elems > 5;
}
}
my @a = 1..4;
my @b = 1..3;
check-array-lengths(@a, @b);
!232
Slide 233
Slide 233 text
Code arguments
To pass along a subroutine as an argument to another
subroutine, pass it by putting the `&` before its name. On the
parameter side, you could happily use a `Scalar`, but using the
`&` sigil there too offers convenient calling.
sub run-without-banned-options(&run, %options, @banned) {
my %filtered = %options;
%filtered{@banned}:delete;
run(|%filtered);
}
sub operate(:$force, :$strip, :$verbose) {
say $force, $strip, $verbose;
}
my %opts = force => 1, verbose => 1;
my @banned = 'force', 'strip';
run-without-banned-options(&operate, %opts, @banned);
!233
Slide 234
Slide 234 text
is copy
Note how we made a copy of the `%options` hash on the previous
slide. We did this so as to avoid modifying the existing one
that was passed to us. We can achieve this more easily with `is
copy`:
sub run-without-banned-options(&run, %options is copy,
@banned) {
%options{@banned}:delete;
run(|%options);
}
sub operate(:$force, :$strip, :$verbose) {
say $force, $strip, $verbose;
}
my %opts = force => 1, verbose => 1;
my @banned = 'force', 'strip';
run-without-banned-options(&operate, %opts, @banned);
!234
Slide 235
Slide 235 text
Try it and see
First, try to write a sub `inc` that, when
passed a variable as an argument, adds one to
it in place (so `my $a = 41; inc($a); say $a;`
gives 42). What happens? Try using `is copy`
and see how it changes (but does not fix) the
problem. Then try out `is rw`.
Next, make your word frequency filter take the
list of blocked words as a named parameter.
Also add a `threshold` named parameter
(defaulted to zero), and don't return any words
with frequencies below the threshold.
!235
Slide 236
Slide 236 text
Classes, attributes,
and methods
(or, "Object-Oriented" programming)
Slide 237
Slide 237 text
–Alan Kay
“I'm sorry that I long ago coined the term 'objects' for
this topic because it gets many people to focus on
the lesser idea. The big idea is 'messaging'…”
Slide 238
Slide 238 text
What are objects?
Objects are autonomous components with
internal state - which we aren't meant to care
about from the outside. Instead, we
communicate with an object entirely by sending
it messages.
In Raku parlance, as in many other languages,
we call message sends "method calls". But we
get better OO designs if we think of them as
sending a message to some independent agent.
!238
Slide 239
Slide 239 text
Declaring a class with attributes
We'll build a simple score keeper for a game where players
earn points. Write class to declare a class, and `has` to
introduce state private to it. Note the `!` twigil means "this is
private to the class".
class ScoreKeeper {
has %!player-points;
}
There are various other forms of attribute declaration, but the
real name of an attribute is always:
$!foo @!foo %!foo &!foo
!239
Slide 240
Slide 240 text
Adding methods
When players earn points, we want to add them. We also
want a method to get the standings. Methods look very
much like subs, except you declare them with method.
method score($player, $points) {
%!player-points{$player} += $points;
}
method ranking() {
%!player-points.pairs.sort({ -.value })
}
!240
Slide 241
Slide 241 text
BUILD
Finally, we need to initialize all players to zero points. (Yes,
Raku does have auto-vivification, but if we rely on that then
our ranking will lack players who never earn points).
We write a `submethod` (a method only callable directly on the
class, not inherited) with the special name BUILD to do this:
submethod BUILD(:@players) {
for @players -> $player {
%!player-points{$player} = 0;
}
}
!241
Slide 242
Slide 242 text
Creating an instance
We can now create a new instance by calling the new method, which we always
inherit. Any named arguments we pass will make it to BUILD:
my $game = ScoreKeeper.new(players => );
We can then use the object as follows:
$game.score('jnthn', 100);
$game.score('lizmat', 150);
for $game.ranking -> $s {
say "$s.key(): $s.value() points";
}
!242
Slide 243
Slide 243 text
Try it and see!
Write a `DaySchedule` class for scheduling hourly appointments.
It should work as follows:
my $sched = DaySchedule.new(opening => 9, closing => 17);
$sched.add-appointment(10, 'Fred'); # Works fine
$sched.add-appointment( 8, 'Brad'); # Dies: too early
$sched.add-appointment(17, 'Anna'); # Dies: too late
$sched.add-appointment( 9, 'Lena'); # Works fine
$sched.add-appointment(10, 'Adam'); # Dies: conflict
If you have free time, add a method that describes the schedule.
!243
Slide 244
Slide 244 text
Roles
A role is a collection of methods, and perhaps attributes, that can be incorporated into a class.
Suppose we wanted to handle point-earning games like those we have so far, along with
games where the winner is the first to reach a goal. We can get some re-use by factoring the
scoring functionality out into a role.
role Scoring {
has %!player-points;
method !zero-scores(@players) {
for @players -> $player {
%!player-points{$player} = 0;
}
}
method score($player, $points) { … }
method ranking() { … }
}
!244
Slide 245
Slide 245 text
Doing a role
The `does` keyword is used to incorporate a role into a class.
class SimpleScoreKeeper does Scoring {
submethod BUILD(:@players) {
self!zero-scores(@players);
}
}
You can incorporate many roles into a class. Any *conflicts* -
where two roles try to provide a method of the same name -
will be identified at compile time.
!245
Slide 246
Slide 246 text
Re-using Scoring
Here's how we can implement the "first to meet the goal" score class.
class FirstToGoalScoreKeeper does Scoring {
has $!goal;
submethod BUILD(:@players, :$!goal) {
self!zero-scores(@players);
}
method winners() {
%!player-points.grep({ .value >= $!goal })
.map({ .key })
}
}
!246
Slide 247
Slide 247 text
Going further
Slide 248
Slide 248 text
!248
• https://docs.raku.org/
The primary source for Raku documentation.
• https://examples.raku.org/
Many examples, including RosettaCode language
comparisons.
• https://raku.org/resources/ and
https://raku.org/
Books, videos, blogs, guides for newcomers, a free
course, and much more!
Where to learn more
Slide 249
Slide 249 text
!249
• IRC: The channels #raku-beginner and #raku on
irc.libera.org are a great places to get help. Many Raku
contributors and users are there, and there is a friendly
atmosphere (please help keep it that way!)
• Discord: https://discord.gg/VzYpdQ6 , usually bridged
to the IRC channels too!
• Mailing list: the perl6-users list is great for questions
are larger than one line, and answers can be more
expansive. Consider subscribing just to see other
people's questions, at https://raku.org/community/
Where to ask questions
Slide 250
Slide 250 text
Q & A ?
(vs. Bonus Topic)
Slide 251
Slide 251 text
Bonus Topics
Cool bits I skipped, that I can speak on easily
Slide 252
Slide 252 text
Bonus topics
!252
Sequences Reduction Operators Hyper Operators Regex
Complex Numbers Creating Operators
List Comprehensions
(ala Python, but better)
Flip-flip Operator
.pick, .roll, and rand Sorting Sets, Bags, and Mixes
Slide 253
Slide 253 text
Non-topics
Each one worth ½ hour or more, so not today
Slide 254
Slide 254 text
Non-topics
!254
Asynchrony
Promises+Supplies+Channel
s
https://docs.raku.org/
language/concurrency
Hyper, Race Grammars Meta Operators
NativeCall Unicode AST
LICENSE
• The license has not yet been discussed (oops).
Until I talk with Johnathan and Patrick, this talk is
not licenced, with copyright shared between the
three of us. If you don't see this slide replaced
with something like CC-BY, you need permission
from all three of us. Hope to resolve before the
end of the conference.