summaryrefslogtreecommitdiffhomepage
path: root/perl6.html.markdown
diff options
context:
space:
mode:
Diffstat (limited to 'perl6.html.markdown')
-rw-r--r--perl6.html.markdown169
1 files changed, 153 insertions, 16 deletions
diff --git a/perl6.html.markdown b/perl6.html.markdown
index fe5b197c..52625bc2 100644
--- a/perl6.html.markdown
+++ b/perl6.html.markdown
@@ -46,18 +46,36 @@ my $inverse = !$bool; # You can invert a bool with the prefix `!` operator
my $forced-bool = so $str; # And you can use the prefix `so` operator
# which turns its operand into a Bool
-## * Arrays. They represent multiple values. Their name start with `@`.
+## * Lists. They represent multiple values. Their name start with `@`.
-my @array = 1, 2, 3;
my @array = 'a', 'b', 'c';
# equivalent to :
-my @array = <a b c>; # array of words, delimited by space.
+my @letters = <a b c>; # array of words, delimited by space.
# Similar to perl5's qw, or Ruby's %w.
+my @array = 1, 2, 3;
say @array[2]; # Array indices start at 0 -- This is the third element
say "Interpolate an array using [] : @array[]";
-#=> Interpolate an array using [] : a b c
+#=> Interpolate an array using [] : 1 2 3
+
+@array[0] = -1; # Assign a new value to an array index
+@array[0, 1] = 5, 6; # Assign multiple values
+
+my @keys = 0, 2;
+@array[@keys] = @letters; # Assign using an array
+say @array; #=> a 6 b
+
+# There are two more kinds of lists: Parcel and Arrays.
+# Parcels are immutable lists (you can't modify a list that's not assigned).
+# This is a parcel:
+(1, 2, 3); # Not assigned to anything. Changing an element would provoke an error
+# This is a list:
+my @a = (1, 2, 3); # Assigned to `@a`. Changing elements is okay!
+
+# Lists flatten (in list context). You'll see below how to apply item context
+# or use arrays to have real nested lists.
+
## * Hashes. Key-Value Pairs.
# Hashes are actually arrays of Pairs (`Key => Value`),
@@ -303,6 +321,37 @@ if long-computation() -> $result {
say "The result is $result";
}
+## Loops can also have a label, and be jumped to through these.
+OUTER: while 1 {
+ say "hey";
+ while 1 {
+ OUTER.last; # All the control keywords must be called on the label itself
+ }
+}
+
+# Now that you've seen how to traverse a list, you need to be aware of something:
+# List context (@) flattens. If you traverse nested lists, you'll actually be traversing a
+# shallow list (except if some sub-list were put in item context ($)).
+for 1, 2, (3, (4, ((5)))) {
+ say "Got $_.";
+} #=> Got 1. Got 2. Got 3. Got 4. Got 5.
+
+# ... However: (forcing item context with `$`)
+for 1, 2, $(3, 4) {
+ say "Got $_.";
+} #=> Got 1. Got 2. Got 3 4.
+
+# Note that the last one actually joined 3 and 4.
+# While `$(...)` will apply item to context to just about anything, you can also create
+# an array using `[]`:
+for [1, 2, 3, 4] {
+ say "Got $_.";
+} #=> Got 1 2 3 4.
+
+# The other difference between `$()` and `[]` is that `[]` always returns a mutable Array
+# whereas `$()` will return a Parcel when given a Parcel.
+
+
### Operators
## Since Perl languages are very much operator-based languages
@@ -359,9 +408,9 @@ $arg ~~ &bool-returning-function; # `True` if the function, passed `$arg`
# This also works as a shortcut for `0..^N`:
^10; # means 0..^10
-# This also allows us to demonstrate that Perl 6 has lazy arrays,
+# This also allows us to demonstrate that Perl 6 has lazy/infinite arrays,
# using the Whatever Star:
-my @array = 1..*; # 1 to Infinite !
+my @array = 1..*; # 1 to Infinite ! `1..Inf` is the same.
say @array[^10]; # you can pass arrays as subscripts and it'll return
# an array of results. This will print
# "1 2 3 4 5 6 7 8 9 10" (and not run out of memory !)
@@ -372,6 +421,13 @@ say @array[^10]; # you can pass arrays as subscripts and it'll return
# Perl 6 will be forced to try and evaluate the whole array (to print it),
# so you'll end with an infinite loop.
+# You can use that in most places you'd expect, even assigning to an array
+my @numbers = ^20;
+@numbers[5..*] = 3, 9 ... * > 90; # The right hand side could be infinite as well.
+ # (but not both, as this would be an infinite loop)
+say @numbers; #=> 3 9 15 21 27 [...] 81 87
+
+
## * And, Or
3 && 4; # 4, which is Truthy. Calls `.Bool` on `4` and gets `True`.
0 || False; # False. Calls `.Bool` on `0`
@@ -700,15 +756,37 @@ try {
open 'foo';
CATCH {
when X::AdHoc { say "unable to open file !" }
- # any other exception will be re-raised, since we don't have a `default`
+ # Any other exception will be re-raised, since we don't have a `default`
+ # Basically, if a `when` matches (or there's a `default`) marks the exception as
+ # "handled" so that it doesn't get re-thrown from the `CATCH`.
+ # You still can re-throw the exception (see below) by hand.
}
}
# You can throw an exception using `die`:
die X::AdHoc.new(payload => 'Error !');
-# TODO warn
-# TODO fail
-# TODO CONTROL
+
+# You can access the last exception with `$!` (usually used in a `CATCH` block)
+
+# There are also some subtelties to exceptions. Some Perl 6 subs return a `Failure`,
+# which is a kind of "unthrown exception". They're not thrown until you tried to look
+# at their content, unless you call `.Bool`/`.defined` on them - then they're handled.
+# (the `.handled` method is `rw`, so you can mark it as `False` back yourself)
+#
+# You can throw a `Failure` using `fail`. Note that if the pragma `use fatal` is on,
+# `fail` will throw an exception (like `die`).
+fail "foo"; # We're not trying to access the value, so no problem.
+try {
+ fail "foo";
+ CATCH {
+ default { say "It threw because we try to get the fail's value!" }
+ }
+}
+
+# There is also another kind of exception: Control exceptions.
+# Those are "good" exceptions, which happen when you change your program's flow,
+# using operators like `return`, `next` or `last`.
+# You can "catch" those with `CONTROL` (not 100% working in Rakudo yet).
### Packages
# Packages are a way to reuse code. Packages are like "namespaces", and any
@@ -1246,7 +1324,7 @@ so 'abc' ~~ / a b* c /; # `True`
so 'abbbbc' ~~ / a b* c /; # `True`
so 'aec' ~~ / a b* c /; # `False`. "b"(s) are optional, not replaceable.
-# - `**` - "Quantify It Yourself".
+# - `**` - (Unbound) Quantifier
# If you squint hard enough, you might understand
# why exponentation is used for quantity.
so 'abc' ~~ / a b ** 1 c /; # `True` (exactly one time)
@@ -1255,6 +1333,27 @@ so 'abbbc' ~~ / a b ** 1..3 c /; # `True`
so 'abbbbbbc' ~~ / a b ** 1..3 c /; # `False` (too much)
so 'abbbbbbc' ~~ / a b ** 3..* c /; # `True` (infinite ranges are okay)
+# - `<[]>` - Character classes
+# Character classes are the equivalent of PCRE's `[]` classes, but
+# they use a more perl6-ish syntax:
+say 'fooa' ~~ / f <[ o a ]>+ /; #=> 'fooa'
+# You can use ranges:
+say 'aeiou' ~~ / a <[ e..w ]> /; #=> 'aeiou'
+# Just like in normal regexes, if you want to use a special character, escape it
+# (the last one is escaping a space)
+say 'he-he !' ~~ / 'he-' <[ a..z \! \ ]> + /; #=> 'he-he !'
+# You'll get a warning if you put duplicate names
+# (which has the nice effect of catching the wrote quoting:)
+'he he' ~~ / <[ h e ' ' ]> /; # Warns "Repeated characters found in characters class"
+
+# You can also negate them ... (equivalent to `[^]` in PCRE)
+so 'foo' ~~ / <-[ f o ]> + /; # False
+
+# ... and compose them: :
+so 'foo' ~~ / <[ a..z ] - [ f o ]> + /; # False (any letter except f and o)
+so 'foo' ~~ / <-[ a..z ] + [ f o ]> + /; # True (no letter except f and o)
+so 'foo!' ~~ / <-[ a..z ] + [ f o ]> + /; # True (the + doesn't replace the left part)
+
## Grouping and capturing
# Group: you can group parts of your regexp with `[]`.
# These groups are *not* captured (like PCRE's `(?:)`).
@@ -1282,7 +1381,7 @@ say $0; # The same as above.
# You might be wondering why it's an array, and the answer is simple:
# Some capture (indexed using `$0`, `$/[0]` or a named one) will be an array
# IFF it can have more than one element
-# (so, with `*`, `+` and any `**`, but not with `?`).
+# (so, with `*`, `+` and `**` (whatever the operands), but not with `?`).
# Let's use examples to see that:
so 'fooABCbar' ~~ / foo ( A B C )? bar /; # `True`
say $/[0]; #=> 「ABC」
@@ -1296,28 +1395,66 @@ say $0.WHAT; #=> (Array)
# A specific quantifier will always capture an Array,
# may it be a range or a specific value (even 1).
-# If you're wondering how the captures are numbered, here's an explanation:
-TODO use graphs from s05
+# The captures are indexed per nesting. This means a group in a group will be nested
+# under its parent group: `$/[0][0]`, for this code:
+'hello-~-world' ~~ / ( 'hello' ( <[ \- \~ ]> + ) ) 'world' /;
+say $/[0].Str; #=> hello~
+say $/[0][0].Str; #=> ~
+# This stems from a very simple fact: `$/` does not contain strings, integers or arrays,
+# it only contains match objects. These contain the `.list`, `.hash` and `.Str` methods.
+# (but you can also just use `match<key>` for hash access and `match[idx]` for array access)
+say $/[0].list.perl; #=> (Match.new(...),).list
+ # We can see it's a list of Match objects. Those contain a bunch of infos:
+ # where the match started/ended, the "ast" (see actions later), etc.
+ # You'll see named capture below with grammars.
## Alternatives - the `or` of regexps
# WARNING: They are DIFFERENT from PCRE regexps.
so 'abc' ~~ / a [ b | y ] c /; # `True`. Either "b" or "y".
so 'ayc' ~~ / a [ b | y ] c /; # `True`. Obviously enough ...
+# The difference between this `|` and the one you're used to is LTM.
+# LTM means "Longest Token Matching". This means that the engine will always
+# try to match as much as possible in the strng
+'foo' ~~ / fo | foo /; # `foo`, because it's longer.
+# To decide which part is the "longest", it first splits the regex in two parts:
+# The "declarative prefix" (the part that can be statically analyzed)
+# and the procedural parts.
+# Declarative prefixes include alternations (`|`), conjuctions (`&`),
+# sub-rule calls (not yet introduced), literals, characters classes and quantifiers.
+# The latter include everything else: back-references, code assertions,
+# and other things that can't traditionnaly be represented by normal regexps.
+#
+# Then, all the alternatives are tried at once, and the longest wins.
+# Exemples:
+# DECLARATIVE | PROCEDURAL
+/ 'foo' \d+ [ <subrule1> || <subrule2> ] /;
+# DECLARATIVE (nested groups are not a problem)
+/ \s* [ \w & b ] [ c | d ] /;
+# However, closures and recursion (of named regexps) are procedural.
+# ... There are also more complicated rules, like specificity
+# (literals win over character classes)
+
+# Note: the first-matching `or` still exists, but is now spelled `||`
+'foo' ~~ / fo || foo /; # `fo` now.
+
+
+
+
### Extra: the MAIN subroutime
# The `MAIN` subroutine is called when you run a Perl 6 file directly.
# It's very powerful, because Perl 6 actually parses the argument
# and pass them as such to the sub. It also handles named argument (`--foo`)
# and will even go as far as to autogenerate a `--help`
-sub MAIN($name) { say "Hello, you !" }
+sub MAIN($name) { say "Hello, $name !" }
# This produces:
# $ perl6 cli.pl
# Usage:
# t.pl <name>
# And since it's a regular Perl 6 sub, you can haz multi-dispatch:
-# (using a "Bool" for the named argument so that we get `--replace`
+# (using a "Bool" for the named argument so that we can do `--replace`
# instead of `--replace=1`)
subset File of Str where *.IO.d; # convert to IO object to check the file exists