Perl 6 Tutorial

Perl 6 TutorialThis tutorial is a 400 page Perl 6 tutorial condensed down into 1 video. Perl 6 is a get it done fast utility language. I’d say it is the most popular utility language. The newest version ads a ton of tools to the original Perl.

I cover Data Types, Conditionals, Strings, Interpolation, Looping, Arrays, Sequences, Maps, Hashes, Subroutines, Recursion, Exceptions, File IO, Shell, Classes, Inheritance, Roles, Regular Expressions, Grammars and more.

If you find tutorials like this useful, consider turning off Ad Blocking software. I only use one 5 second skippable ad during this entire 1 1/2 hour video. I’d greatly appreciate it if you don’t block it. Thank you 🙂

Cheat Sheet / Transcript

# Install : https://www.rakudo.org/files/star/third-party

#`( multiline or inline
comment
)

# Most data in Perl 6 are objects

# ---- BASICS ----

# Output the string + newline
put 'Hello World';

# Receive user input and save to the variable $name
# my declares a variable
# The sigil $ comes before the variable name
# if you want the value to be changeable (mutable)
my $name = prompt "What's your name? ";
put "Hello $name";

# say normally provides the same output as put
# but it may abbreviate it
put 1 .. 10;
say 1 .. 10;

# print doesn't add a newline
print "No newline";

# ---- VARIABLES ----
# Variable names start with a letter or number
# and can contain underscores, hyphens and
# apostrophes

# You can declare an immutable (unchangeable)
# variable with \
my \pi = 3.1415;
# This would cause an error -> pi = 6;

# You can define types or not
# Common types : Bool, Int, Num (float),
# Real (Non-complex number), Str, Date
my Int $x;
# This would cause an error -> $x = "Dog";

my $y = 6;
$y = "Dog";

# The binding operator creates an alias to
# a variable
my $z := $y;
put $z;

# Booleans are True or False
# 0 is considered false everything else is true
my Bool $can-vote = True;
put $can-vote;

# You can use exponential notation
my $thousand = 1e3;

# Show types
put "10 : ", 10.^name;
put "10.5 : ", (10.5).^name;
put "\"10\" : ", "10".^name;

# Convert int as unicode to character
say '65'.chr;

# Convert numbers to strings
say "Type : ", (10.Str).^name;

# Convert strings to numbers
say "Type : ", (+"123").^name;

# Auto casting works
say "1 + 2 = ", "1" + 2;

# ---- MATH ----
# You can use common math functions
# This is another way to format output
# %d Integers, %f Floats, %s
say (5 + 4).fmt("5 + 4 = %d");
say (5 - 4).fmt("5 - 4 = %d");
say (5 * 4).fmt("5 * 4 = %d");

# Format float with 2 decimals
say (5 / 4).fmt("5 / 4 = %.2f");
say (5**4).fmt("5^4 = %d");

# Adding fractions
say (1/4 + 1/2).fmt("1/4 + 1/2 = %.2f");

# Generate random number between 0 and 20
say "Random : ", 20.rand.Int;

# Generate random value from range 5 to 20
say "Random Range : ", (5..20).rand.Int;

# You can expect 15 digits of precision
my $floatNum = 1.111111111111111111111111111111111111;
my $floatNum2 = 1.111111111111111111111111111111111111;
say "Big Float : ", $floatNum + $floatNum2;

# With math functions you can normally use
# funcName(), or attr.funcName
say "(-1).abs = ", (-1).abs;
say "1.exp = ", (1).exp; # e to the power of
say "sqrt(9) = ", sqrt(9);
say "log(2) = ", log(2);
say "log10(2) = ", log(100);
say "round(2.45) = ", round(2.45);
say "floor(2.45) = ", floor(2.45);
say "ceiling(2.45) = ", ceiling(2.45);

say "sin(0) = ", sin(0);
say "cos(0) = ", cos(0);
say "tan(0) = ", tan(0);
say "asin(0) = ", asin(0);
say "acos(0) = ", acos(0);
say "atan(0) = ", atan(0);
say "cotan(0) = ", cotan(0);
say "acotan(0) = ", acotan(0);
say "sinh(0) = ", sinh(0);
say "cosh(0) = ", cosh(0);
say "tanh(0) = ", tanh(0);
say "asinh(0) = ", asinh(0);
say "acosh(0) = ", acosh(0);
say "atanh(0) = ", atanh(0);
say "atan2(100) = ", atan2(100);

# ---- CONDITIONALS ----
# Conditional Operators  > < >= <= == !-
# Logical Operators : && and, || or, ! not

my $age = 12;
if $age >= 5 && $age <= 6 {
  put "Go to Kindergarten";

  # Shortcut chained comparison
} elsif 7 <= $age <= 13 {
  put "Go to Middle School";
} elsif $age >= 14 && $age <= 18 {
  put "Go to High School";
} else {
  put "Stay Home";
}

# Execute only if true
put 'Old enough for school' if $age >= 5;

# Execute if condition is false
my $k = 0;
unless $k == 5 {
  put $k;
}

# Ternary operator : If true use 1st
# otherwise use 2nd as output
put 'Can vote : ', $age >= 18 ?? 'True' !! 'False';

# ---- STRINGS -----
# Create a string
my $str1 = "Hello";

# You can use variables in output with ""
say "$str1";

# Use quotes by escaping
# \n, \t, \r, \b, \a, \f
say "I like \"quotes\"";

# Number of characters
say "Num : ", $str1.chars;

# Does it have a value
say "Has Value : ", ?$str1;

# To use protected characters surround
# the output with Q and delimiters
say Q/$str1 is ok here/;

# You can also use single quotes
say '$str1 is ok here';

# Concatenate STRINGS
say "one " ~ "string";

# Join also concatenates and puts the first
# string between the next 2 or more
my $str2 = join " ", "a", "long", "string";
say $str2;

# Multiline strings
my $str3 = q :heredoc/END/;
I go
for
many
lines
END
say $str3;

# Does a string contain a string
say "Long? ", $str2.contains("long");

# Add fc to make it case insensitive
say "Long? ", $str2.fc.contains("long");

# Get index where you have a match
my $sI = $str2.index("long");

# Get a substring starting with index 0
# You can often use : instead of ()s with functions
say $str2.substr: $sI, 5;

# Trim whitespace
# Also .trim-leading & .trim-trailing
say "Bye whitespace : ", "     abc   ".trim;

# Lowercase, uppercase, titlecase
say "ABC".lc;
say "abc".uc;
say "abc".tclc;

# Are strings equal
say "Dog".lc eq "dog";

# Greater than is based on alphabetical
# order and uppercase > Lowercase
# Also there is lt
say "GT : ", "abc" gt "d";

# Remove last character
say "abc".chop;

# Remove a newline
say "abc\n".chomp;

# Use variables without spaces
say "{$str1}, Derek";

# Code in strings
say "5 * 4 = {5*4}";

# Use interpolation only between braces
say q :c "\n 1 + 2 = {1+2}";

# Get character by Code
say "\x[40]";

# Duplicate strings
say $str1 x 5;

# Split based on delimiter
say split(', ', "a, b, c");

# Split using Regex
say split(/<[;,]>/, "a,b;c");

# Split using another Regex
say "a b c".split: / \s /;

# Replace matches
my $str5 = "Derek is terrible";
put $str5.subst: /terrible/, 'Awesome';

# ---- LOOPING ----
# Execute as long as a condition is true
loop (my $i = 1; $i < 20; $i++){

  # Print only even numbers
  if $i mod 2 == 0 {
    put $i;

    # Like continue in other languages
    next;
  }
  if $i >= 10 {

    # Jumps out of loop like break
    last;
  }
}

# Print 0 .. 4
loop {
  # Marking this as state sets the value
  # only one time
  state $j = 0;

  # Print and then add 1
  put $j++;

  # Leave loop when true
  last if $j == 5;
}

# While loop
my $i1 = 0;
while $i1 < 5 {
  put $i1++;
}

# Repeat while executes once and then checks
# the condition
repeat while $i1 < 5 {
  put $i1++;
}

loop {
  state $k = 0;
  put $k++;
  last if $k >= 5;

  # Phasers run at the beginning and
  # end of a loop
  FIRST {say "Starting"}
  LAST {say "Ending"}
}

# ---- BLOCKS ----
# You can store blocks of Code
# $_ represents a passed parameter
my $sayHello := { say "Hello $_"};
$sayHello("Derek");

# Use multiple parameters
my $addNums := {$^a + $^b};
say $addNums(1,2);

# You can use Thunks (*) to create closures
# or Whatever codes
my $plus2 = * + 2;
say $plus2(5);

# Subsets can be used to create data types
# that only hold evens for example
subset EvenInt of Int where { $^a mod 2 == 0 };
my EvenInt $eVal = 4;
say $eVal;

# ---- LISTS & ARRAYS ----
# An immutable series of values
my $l1 = List.new: 1, 2, 3;

# Using @ instead of $ provides for shortcuts
# and you create an array thats values can
# be changed
my @l2 = (1, 2, 3);

# Get number of values
say $l1.elems;
say @l2.elems;

# Create a list with values separated by
# spaces
my @l3 = <Mark Sally Paul Sam>;
say @l3.elems;

# Get a value by index
put @l3[0];

# Get a range of values
put @l3[0, 1];

# Change a value
@l3[2] = "Pam";

# Shift off the 1st array element
put @l3.shift;

# Shift a new value on the front
@l3.unshift: <Peter Pat>;

# Pop off the last
put @l3.pop;

# Push items onto the end
@l3.push: <Zack>;

# Splice off values by index
@l3.splice: 0, 2;

# Search for a match
say "Pam : ", @l3.grep("Pam");

# Filter a list
say "Evens ", (1..10).grep: {$_ %% 2};

# Cycle through list with for
for @l3 {
  # $_ is the topic variable
  say "$_";
}

# Get multiple values at once
for @l3 -> $x, $y {
  say "$x $y";
}

# Get key and index
for @l3.kv -> $index, $item {
  say "index $index : item $item";
}

# Sort lists
say sort @l3;

# Create a list of lists
my $l4 = ( <1 2>, <3 4> );
say "00 : ", $l4[0][0];

# Combine 2 lists into one
say zip( <a b>, <1 2>);

# Declare 2 variables at once
my ($val2, $val3) = <a b>;

# Store variables in lists without commas
my $l5 = <<$val2 $val3>>;
put $l5;

# Output with delimiters
put $l5.join(', ');

# Turn a string into an array
# .comb creates a list of characters
my $str4 = "a b c d";
my $l6 = $str4.words;
put $l6;

# Reverse list
put $l6.reverse;

# Maps allow us to transform each element of
# an array (Multiply every value by 2)
my @l7 = 1, 2, 3;
my @map1 = map { $_ * 2 }, @l7;
say @map1;

# Add 2 lists with a hyperoperator
# You can use -, *, /
my @l8 = 4, 5, 6;
say @l7 <<+>> @l8;

# ---- RANGES ----
# You can create ranges of values as
# long as they are in order 1,2,3 a,b,c
# Ranges are not lists
my $r1 = 1 .. 5; # Not 5 .. 1

# Turn a range into a list
my $rl1 = $r1.List;

# Exclude left or right most value
my $r2 = 1 ^.. 5;
my $r3 = 1 ..^ 5;

# ---- SEQUENCES ----
# Sequences are lists that defer the
# creation of values and then doesn't
# store them
my $seq1 := 1 ... 10;

# Sequences can count down
my $seq2 := 10 ... 1;

# They can be created using an algorithm
# Fibonacci series : 1,1,2,3,5,8,13,
my $fib := 0, 1, -> $a, $b { $a + $b } ... *; 1;
put $fib[^10].join(', ');

# Check for lazy lists
put "Lazy : ", $fib.is-lazy;

# ---- SETS ----
# Sets are lists with no duplicates
my $mySet = set(1,2,3,3);
say $mySet.elems;

# ---- MAPS ----
# Maps are immutable lists of ky value pairs
my $japFam = Map.new:
  'Dad', 'Otousan',
  'Mom', 'OKaasan',
  'Son', 'Oniisan',
  'Daughter', 'Oneesan';

# Get value with key
say $japFam<Dad>;

# Check if exists
say $japFam{'Mom'}:exists;

# Get keys and values
for $japFam.kv -> $key, $item {
  put "$key => $item";
}

# ---- HASHES ----
# Mutable maps
my $japColor = Hash.new:
  'Blue', 'Aoo',
  'Red', 'Aka',
  'Green', 'Midori';

# Change a value
$japColor<Blue> = 'Ao';

# Delete kv
$japColor<Blue>:delete;

# Add kv
$japColor<White> = "Shiro";

# Get KVs
for $japColor.kv -> $key, $item {
  put "$key => $item";
}

# ---- SUBROUTINES / FUNCTIONS ----
# Subroutines use return to return values

# sub name (arguments with or without types)
# You can give default values if you want
sub addNums2 ($a = 1, $b = 1){
  return $a + $b;
}
say "1 + 3 = ", addNums2(1,3);

# Arguments can be optional
sub giveMe ($arg?){
  return $arg;
}
say giveMe();
say giveMe(1);

# Store function in a variable
my &sub1 = &addNums2;
say &sub1(1,3);

# Use a slurpy parameter to accept an
# unknown number of arguments
sub addNums3(*@nums){
  state $sum = 0;
  for @nums -> $num {
    $sum = $sum + $num;
  }
  return $sum;
}
say "Sum : ", addNums3 1, 2, 3, 4 ;

# Return multiple values
sub nextTwo($a){
  return $a + 1, $a + 2;
}
say nextTwo(1);

# You can pass a function as a value
# for example to square values in a list
sub square($a){ $a * $a };
my @squaredList = map &square, 1..5;
say join ', ', @squaredList;

# Recursion is when a function calls itself
# Calculate a factorial
sub factorial($a){
  if ($a == 1) {
    return 1;
  } else {
    return $a * factorial($a - 1);
  }
}
say factorial(4);
# 1st : result = 4 * factorial(3) = 4 * 6 = 24
# 2nd : result = 3 * factorial(2) = 3 * 2 = 6
# 3rd : result = 2 * factorial(1) = 2 * 1 = 2

# ---- EXCEPTION HANDLING ----
# We can set up our code to catch errors

# Surround problematic code with try
try {
  # my $ans = (10 %% 0);

  # Throw your own exception
  die 'Bad Stuff';

  # List exceptions to catch here
  CATCH {
    # $_ stores the error message
    when X::Numeric::DivideByZero {
      say "Error : $_";
    }
    default {
      say "Default : $_";
    }
  }
}

# ---- FILE I/O ----
# Create a file for writing
my $f1 = open "mydata", :w;

# Write text to it
$f1.print("file stuff\n");
my $myName = "Derek";
$f1.printf("My name is %s\n", $myName);

# Close file
$f1.close;

# spurt opens, writes and closes the file
# Remove :append to overwrite
spurt "mydata", "spurts stuff\n", :append;

# Read from a file
my $f2 = open "mydata", :r;
my $myData = $f2.slurp;
say $myData;
$f2.close;

# ---- FILE MANIPULATION ----
# Check if file exists
if "mydata".IO.e {
  say "Exists";

  # When was file edited
  say "mydata".IO.modified.DateTime;
  # Read
  say "mydata".IO.accessed.DateTime;
  # Size
  say "mydata".IO.s;
}

# Rename file
rename "mydata", "mydata2";

# Copy file
copy "mydata2", "mydataBU";

# Make a directory
mkdir "Perl Stuff";

# Does directory exist
say "Perl Stuff".IO.d;

# Get directory listing
say dir;

# Remove empty directory
rmdir "Perl Stuff" or die "$!";

# You can run any shell commands
shell('ls -l');

# Store the result of the command
my $shellOP = Q:x{ls -l};

# ---- GRABBING DATA & MODULES ----
# zef is used to install modules that
# provide premade functions and such
# Modules : modules.perl6.org
# Install Popular : zef install Task::Popular

# Install HTTP::UserAgent with
# zef install HTTP::UserAgent

# Used to fetch data
use HTTP::UserAgent;
my $uA = HTTP::UserAgent.new;

# How long to wait
$uA.timeout = 10;

# The URL
my $url = "http://www.gutenberg.org/cache/epub/58670/pg58670.txt";

# See if you can get the data
my $response = $uA.get($url);

my $dW;

# Get data or fail
if $response.is-success {
    $dW = $response.content;
} else {
    die $response.status-line;
}

# Output 10 lines
for $dW.lines(10) -> $text {
  say $text;
}

# ---- CLASSES ----
# Classes simulate real world objects by
# defining attributes and capabilities (methods)

class Animal {

  # Create a private attribute with $!
  has $!name = '';

  # Public with $. (Make read/writable)
  # Define data type or don't
  has Real $.height is rw = 0.0;
  has $.weight is rw = 0.0;

  # Constructor that is called when an
  # object is created
  # The ! after name requires its value
  method BUILD(:$name!, :$height, :$weight) {
    $!name = $name;

    # Handle if values aren't passed
    if $height {
      $.height = $height;
    } else {
      $.height = 0;
    }

    if $weight {
      $.weight = $weight;
    } else {
      $.weight = 0;
    }
  }

  # Provides access to the name (Getter)
  method name { $!name; }

  # You could make name mutable
  # method name is rw { $!name; }

  # Self provides a way to refer to an object
  method info {
    return "{self.name} is {self.height}cms tall and
    {self.weight}kgs";
  }

  # This is an abstract method subclasses
  # will implement
  method makeSound { !!! }

}

# Create an Animal
my $spot = Animal.new:
:name('Spot')
:height(63)
:weight(40);

# Get the name value
say $spot.name;

# This would throw an error without is rw
# $spot.name = 'dog';

$spot.height = 63.5;
$spot.weight = 35.5;
say $spot.info;

# ---- INHERITANCE ----
# Inheriate methods and attributes from Animal
class Dog is Animal {
  has $.sound is rw = "Woof";

  # Overwrite method
  method info {
    # callsame executes the superclass function
    # with the same name
    my $origMsg = callsame;
    # Combine the strings with ~
    return $origMsg ~ " and says {self.sound}";
  }

  # Implement the abstract method
  method makeSound {
    return "{self.name} says {self.sound}";
  }
}

my $doug = Dog.new:
:name('Doug')
:height(63);
say $doug.name;
say $doug.weight;
say $doug.info;

# ---- ROLES ----
# You can add capabilities to objects
# with roles

role AreaRole {
  has $.length is rw;
  has $.width is rw;
  has $.radius is rw;

  method circA {
    return pi * ($.radius ** 2);
  }

  method rectA {
    return $.length * $.width;
  }
}

# Inherite the role in a class
class Shape does AreaRole {};
my $circle = Shape.new:
:radius(10);
say $circle.circA;

# ---- REGULAR EXPRESSIONS ----
# Regular Expressions (Regex) are used to
# 1. Search for a specific string in a large amount of data
# 2. Verify that a string has the proper format (Email, Phone #)
# 3. Find a string and replace it with another string
# 4. Format data into the proper form for importing for example

my $regStr1 = "Random words";

# You can use specific characters between
# m/stuff/
if $regStr1 ~~ m/word/ { put "Found word" };

# Search for whitespace with \s
if $regStr1 ~~ m/\s/ { put "Found space" };

# Backslashed Character Classes
# The uppercase same character is a match
# for anything except that match
# \n : Newline
# \h : Horizontal Whitespace
# \t : Tab
# \s : Whitespace
# \d : Digit
# \w : Letter, number or underscore
# . : Any single character
# + : 1 or More
# * : 0 or more
# ? : 0 or 1

# Search arrays
my @nA1 = (1, 2, 3, 4);
if @nA1 ~~ m/2/ { put "Found 2" };

# Match ranges of values and store regex
my $reg1 = rx/ <[ a .. d 1 2 3]>* /;

# Returns the 1st match
say "c e b 4" ~~ $reg1;
say @nA1 ~~ $reg1;

# Get all matches with m:global
my @matches = "cat and cat" ~~ m:global/cat/;
say @matches;
say +@matches;

my $regstr2 = "Cat rat mat fat pat dog";

# Any single character followed by at
my @matches2 = $regstr2 ~~ m:global/ \w+at /;
say @matches2;

# Only Cat, rat and mat (:i Ignores case)
my @matches3 = $regstr2 ~~ m:global:i/ <[crm]>+at /;
say @matches3;

# Anything except Cat, rat and mat
my @matches4 = $regstr2 ~~ m:global:i/ <-[crm]>+at /;
say @matches4;

# Match any character and periods
my $regstr3 = "F.B.I. I.R.S. CIA";
say $regstr3 ~~ m:global/ .\..\.. /;

# Match only 5 digit numbers
my $regstr4 = "12 12345 123";
say $regstr4 ~~ m:global/ \d ** 5 /;

# Match 3 through 5 digit numbers
say $regstr4 ~~ m:global/ \d ** 3..5 /;

# Check for phone number
my $regstr5 = "412-555-1212 88";
say $regstr5 ~~ m:global/ \d**3 \- \d**3 \- \d**4 /;

# Match 0 or 1
my $regstr6 = "cat cats";
say $regstr6 ~~ m:global/ <[cat]>+s? /;

# Match 0 or more
my $regstr7 = "doctor doctors doctor's";
say $regstr7 ~~ m:global/ <[doctr]>+<['s]>* /;

# Capture part of a match
my $regstr8 = "abcd";
say $regstr8 ~~ m:global/ (a)bc(d) /;

# Capture when 1 or another matches
my $regstr9 = "ab cb db";
say $regstr9 ~~ m:global/ [a||c] b /;

# Greedy & Lazy Matching
my $regstr10 = "catcatcat";
say $regstr10 ~~ m:global/ c .* t /; # Greedy
say $regstr10 ~~ m:global/ c .*? t /; # Not Greedy

# Whitespace isn't considered unless you use :s
my $regstr11 = "1 2 3";
say $regstr11 ~~ m:global/ 1  2  3 /;
say $regstr11 ~~ m:global/:s 1  2  3 /;

# ---- GRAMMARS ----
# Grammars are classes used to parse complex text

# Parse for numbers
grammar Number {
  # The first rule is called TOP
  # May contain a negative and 1 or more numbers
  # and maybe a .
  token TOP { \-? \d+ [\. \d+]? }
}

# Cycle through a list of numbers
for <1 23 -456 2.35> -> $num {
  say Number.parse($num);
}

# You can create multiple tokens each with
# their own rules
grammar Number2 {
  # Will get its sum match using tokens below
  token TOP {
    <sign>?<value>
  }
  token sign {
    '-'
  }
  token number {
    \d+
  }
  # Combination of all the above
  token value {
    | <number>
    | "." <number>
    | <number> "."
    | <number> "." <number>
  }
}

# Cycle through a list of numbers
for <1 23 -456 2.35> -> $num {
  say Number2.parse($num);
}

Leave a Reply

Your email address will not be published. Required fields are marked *