summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNami-Doc <vendethiel@hotmail.fr>2014-07-24 23:05:44 +0200
committerNami-Doc <vendethiel@hotmail.fr>2014-07-24 23:05:44 +0200
commit38c167867203d6192060a853ceae4c47eee581ad (patch)
tree1823e80231ddbcc5f3ad89d5519e2886a0f9d789
parent1d931a37f2d428bc2d783f1a8597455db70a23de (diff)
More on sub arguments.
Declare your own subs !! More on hash: add colonpair syntax Flatten argument list with `|` Multi on :$! TODO: `MAIN` TODO: meta ops
-rw-r--r--perl6.html.markdown232
1 files changed, 222 insertions, 10 deletions
diff --git a/perl6.html.markdown b/perl6.html.markdown
index 5ead6560..d7864b7f 100644
--- a/perl6.html.markdown
+++ b/perl6.html.markdown
@@ -35,6 +35,10 @@ my $str2 = "String"; # double quotes allow for interpolation
# variable names can contain but not end with simple quotes and dashes, and can contain (and end with) underscores :
# my $weird'variable-name_ = 5; # works !
+my $bool = True; # `True` and `False` are Perl 6's boolean
+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. They start with `@`
my @array = 1, 2, 3;
@@ -44,14 +48,26 @@ my @array = <a b c>; # array of words, delimited by space. similar to perl5's qw
say @array[2]; # Array indices start at 0 -- This is the third element
-## - Hashes
+say "Interpolate an array using [] : @array[]"; #=> Interpolate an array using [] : a b c
+
+## - Hashes. Key-Value Pairs.
+# Hashes are actually arrays of Pairs (`Key => Value`), "flattened" to remove duplicated keys.
my %hash = 1 => 2,
3 => 4;
-my %hash = autoquoted => "key",
+my %hash = autoquoted => "key", # keys are auto-quoted
"some other" => "value", # trailing commas are okay
;
-my %hash = <key1 value1 key2 value2> # you can also create a hash from an even-numbered array
+my %hash = <key1 value1 key2 value2>; # you can also create a hash from an even-numbered array
+my %hash = key1 => 'value1', key2 => 'value2'; # same as this
+
+# You can also use the "colon pair" syntax: (especially handy for named parameters that you'll see later)
+my %hash = :w(1), # equivalent to `w => 1`
+ # this is useful for the `True` shortcut:
+ :truey, # equivalent to `:truey(True)`, or `truey => True`
+ # and for the `False` one:
+ :!falsey, # equivalent to `:falsey(False)`, or `falsey => False`
+ ;
say %hash{'key1'}; # You can use {} to get the value from a key
say %hash<key2>; # if it's a string, you can actually use <>
@@ -69,6 +85,123 @@ sub say-hello-to(Str $name) { # you can provide the type of an argument
my &s = &say-hello;
my &other-s = sub { say "anonymous function !" }
+# A sub can have a "slurpy" parameter, or "doesn't-matter-how-many"
+sub as-many($head, *@rest) { # the `*@` slurpy will basically "take everything else".
+ # Note: you can have parameters *before* (like here) a slurpy one, but not *after*.
+ say @rest.join(' / ') ~ " !";
+}
+say as-many('Happy', 'Happy', 'Birthday'); #=> Happy Birthday !
+ # Note that the splat did not consume the parameter before.
+
+## You can call a function with an array using the "argument list flattening" operator `|`
+# (it's not actually the only feature of the operator, but it's one of them)
+sub concat3($a, $b, $c) {
+ say "$a, $b, $c";
+}
+concat3(|@array); #=> a, b, c
+ # `@array` got "flattened" as a part of the argument list
+
+## It can also have optional arguments:
+sub with-optional($arg?) { # the "?" marks the argument optional
+ say "I might return `(Any)` if I don't have an argument passed, or I'll return my argument";
+ $arg;
+}
+with-optional; # returns Any
+with-optional(); # returns Any
+with-optional(1); # returns 1
+
+## You can also give them a default value when they're not passed:
+sub hello-to($name = "World") {
+ say "Hello, $name !";
+}
+hello-to; #=> Hello, World !
+hello-to(); #=> Hello, World !
+hello-to('You'); #=> Hello, You !
+
+## You can also, by using a syntax akin to the one of hashes (yay unification !),
+## pass *named* arguments to a `sub`.
+sub with-named($normal-arg, :$named) {
+ say $normal-arg + $named;
+}
+with-named(1, named => 6); #=> 7
+with-named(2, :named(5)); #=> 7
+with-named(3, :4named); #=> 7
+ # (special colon pair syntax for numbers)
+
+with-named(3); # warns, because we tried to use the undefined $named
+ # in a `+`: by default, named arguments are *optional*
+
+# To make a named argument mandatory, you can use `?`'s inverse, `!`
+sub with-mandatory-named(:$str!) {
+ say "$named !";
+}
+with-mandatory-named(str => "My String"); #=> My String
+with-mandatory-named; # run time error: "Required named parameter not passed"
+with-mandatory-named(3); # run time error: "Too many positional parameters passed"
+
+## If a sub takes a named boolean argument ...
+sub takes-a-bool($name, :$bool) {
+ say "$name takes $bool";
+}
+# ... you can use the same "short boolean" hash syntax:
+takes-a-bool('config', :bool); # config takes True
+takes-a-bool('config', :!bool); # config takes False
+# or you can use the "adverb" form:
+takes-a-bool('config'):bool; #=> config takes True
+takes-a-bool('config'):!bool; #=> config takes False
+# You'll learn to love (or maybe hate, eh) that syntax later.
+
+
+## You can also provide your named arguments with defaults:
+sub named-def(:$def = 5) {
+ say $def;
+}
+named-def; #=> 5
+named-def(:10def); #=> 10
+named-def(def => 15); #=> 15
+
+## There's more to come, but we're going to end this paragraph with a really powerful feature:
+## Unpacking ! It's the ability to "extract" arrays and keys. It'll work in `my`s and parameters.
+my ($a, $b) = 1, 2;
+say $a; #=> 1
+my ($, $, $c) = 1, 2, 3; # keep the non-interesting anonymous
+say $c; #=> 3
+
+my ($head, *@tail) = 1, 2, 3; # Yes, it's the same as with "slurpy subs"
+my (*@small) = 1;
+
+sub foo(@array [$fst, $snd]) {
+ say "My first is $fst, my second is $snd ! All in all, I'm @array[]."; # (remember the `[]` to interpolate the array)
+}
+foo(@tail); #=> My first is 2, my second is 3 ! All in all, I'm 1 2
+
+
+# If you're not using the array itself, you can also keep it anonymous, much like a scalar:
+sub first-of-array(@ [$fst]) { $fst }
+first-of-array(@small); #=> 1
+first-of-array(@tail); # errors with "Too many positional parameters passed" (the array is too big)
+
+# You can also use a slurp ...
+sub slurp-in-array(@ [$fst, *@rest]) { # you could decide to keep `*@rest` anonymous
+ say $fst + @rest.elems;
+}
+slurp-in-array(@tail); #=> 3
+
+# You could even extract on a slurpy (but it's pretty useless ;-).)
+sub fst(*@ [$fst]) { # or simply : `sub fst($fst) { ... }`
+ say $fst;
+}
+fst(1); #=> 1
+fst(1, 2); # errors with "Too many positional parameters passed"
+
+# Lou can also destructure hashes (and classes, which you'll learn about later !)
+sub key-of(% (:value($val), :qua($qua))) {
+ say "Got val $val, $qua times.";
+}
+# Then call it with a hash: (you need to keep the brackets for it to be a hash)
+key-of({value => 1});
+#key-of(%hash); # the same (for an equivalent `%hash`)
+
# `->`, lambda with arguments, and string interpolation
my &lambda = -> $argument { "The argument passed to this lambda is $argument" }
# We're going to see how powerful Perl 6 subs are just a little down below, after seeing the basics of operators
@@ -225,7 +358,7 @@ say @array[^10]; # you can pass arrays as subscripts and it'll return an array o
# Note : when reading an infinite list, Perl 6 will "reify" the elements it needs, then keep them in memory
# They won't be calculated more than once.
-# Warning, though : if you try this example in the REPL and juste put `1..*`,
+# Warning, though: if you try this example in the REPL and juste put `1..*`,
# Perl 6 will be forced to try and evaluate the whole array (to print it),
# so you'll end with an infinite loop.
@@ -252,12 +385,12 @@ say @primes[^10]; #=> 1 1 2 3 5 8 13 21 34 55
# Note : as for ranges, once reified, elements aren't re-calculated.
# That's why `@primes[^100]` will take a long time the first time you print it, then be instant
-## More on Subs !
-# Perl 6 likes functions. So, in Perl 6, functions are very powerful:
+### More on Subs !
+# Perl 6 likes functions. So, in Perl 6, they are very powerful:
## Multiple Dispatch
# Perl 6 can decide which variant of a `sub` to call based on the type of the arguments,
-# or on arbitrary preconditions, using `where` :
+# or on arbitrary preconditions, like with a type or a `where`:
# with types
multi sub sayit(Int $n) { # note the `multi` keyword here
@@ -270,13 +403,32 @@ sayit("foo"); # prints "String: foo"
sayit(True); # fails at *compile time* with "calling 'sayit' will never work with arguments of types ..."
# with arbitrary precondition:
-multi is-big(Int $n where * > 10) { True }
-multi is-big(Int $) { False }
+multi is-big(Int $n where * > 50) { "Yes !" } # using a closure
+multi is-big(Int $ where 10..50) { "Quite." } # this uses smart-matching (could use a regexp, etc)
+multi is-big(Int $) { "No" }
# you can also name these checks, by creating "subsets":
subset Even of Int where * %% 2;
+multi odd-or-even(Even) { "Even" } # the main case using the type. We don't name the argument
+multi odd-or-even($) { "Odd" } # "else"
+
+# You can even dispatch based on a positional's argument presence !
+multi with-or-without-you(:$with!) { # make it mandatory to be able to dispatch against it
+ say "I can live ! Actually, I can't.";
+}
+multi with-or-without-you {
+ say "Definitely can't live.";
+}
+# This is very, very useful for many purposes, like `MAIN` subs (covered later),
+# and even the language itself is using it in several places.
+# `is`, for example, is actually a `multi sub` named `trait_mod:<is>`, and it works off that.
+# `is rw`, for example, is a dispatch to a function with this signature:
+# sub trait_mod:<is>(Routine $r, :$rw!) {}
+# (commented because running this would probably lead to some surprising side-effects !)
+
+# ----
# The last expression of a sub is returned automatically (though you may use the `return` keyword, of course):
sub next-index($n) {
$n + 1;
@@ -626,7 +778,67 @@ $a ! $b ! $c; # with a list-associative `!`, this is `infix:<>`
!$a! # with right-associative `!`, this is `!($a!)`
!$a! # with non-associative `!`, this is illegal
-## Last part of the operator list :
+## Create your own operators !
+# Okay, you've been reading all of that, so I guess I should try to show you something exciting.
+# I'll tell you a little secret (actually not): In Perl 6, all operators are actually just funny-looking subroutines.
+# You can declare an operator just like you declare a sub:
+sub prefix:<win>($winner) { # refer to the operator categories
+ # (yes, it's the "words operator" `<>`)
+ say "$winner Won !";
+}
+win "The King"; #=> The King Won !
+ # (prefix is before)
+
+# you can still call the sub with its "full name"
+say prefix:<!>(True); #=> False
+
+sub postfix:<!>(Int $n) {
+ [*] 2..$n; # using the reduce meta-operator ... See below ;-) !
+}
+say 5!; #=> 120
+ # (postfix is after)
+
+
+sub infix:<times>(Int $n, Block $r) { # infix in the middle
+ for ^$n {
+ $r(); # needs the parentheses because it's a scalar
+ }
+}
+3 times -> { say "hello" }; #=> hello
+ #=> hello
+ #=> hello
+
+# For circumfix and post-circumfix ones
+sub circumfix:<[ ]>(Int $n) {
+ $n ** $n
+}
+say [5]; #=> 3125
+ # circumfix is around
+
+sub postcircumfix:<{ }>(Str $s, Int $idx) { # post-circumfix is "after a term, around something"
+ $s.substr($idx, 1);
+}
+say "abc"{1}; #=> b
+ # after the term `"abc"`, and around the index (1)
+
+# This really means a lot -- because everything in Perl 6 uses this.
+# For example, to delete a key from a hash, you use the `:delete` adverb (named argument)
+%h{$key}:delete;
+# equivalent to:
+postcircumfix:<{ }>(%h, $key, :delete);
+# It's *all* using the same building blocks! Syntactic categories (prefix infix ...),
+# named arguments (adverbs), ..., used to build the language are available to you.
+
+# (you are, obviously, recommended against making an operator out of *everything* --
+# with great power comes great responsibility)
+
+## Meta operators !
+# Oh boy, get ready. Get ready, because we're dwelving deep into the rabbit's hole, and you probably won't want
+# to go back to other languages after reading that (I'm sure you don't want to already at that point).
+
+# - Reduce meta-operator
+
+## End of the operator list:
## * Sort comparison
# They return one value of the `Order` enum : `Less`, `Same` and `More` (which numerify to -1, 0 or +1).