Skip to content

Commit

Permalink
make examples compile, fix broken examples
Browse files Browse the repository at this point in the history
  • Loading branch information
gfldex committed Aug 11, 2016
1 parent 97a01da commit 1606ce2
Showing 1 changed file with 119 additions and 128 deletions.
247 changes: 119 additions & 128 deletions doc/Language/functions.pod6
Expand Up @@ -79,9 +79,7 @@ L<Block> syntax. It's used after every C<if>, C<for>, C<while>, etc.
for 1, 2, 3, 4 -> $a, $b {
say $a ~ $b;
}
12
34
# OUTPUT«12␤34␤»
They can also be used on their own as anonymous blocks of code.
Expand Down Expand Up @@ -128,11 +126,13 @@ may be supplied in any order, but it is considered good form to
place named arguments after positional arguments. Inside the
argument list of a function call, some special syntax is supported:
f :named(35) # A named argument (in "adverb" form.)
f named => 35 # Also a named argument.
f :35named # A named argument using abbreviated adverb form
f 'named' => 35 # Not a named argument, a Pair in a positional argument
f |$c # Merge the contents of Capture $c as if they were supplied
sub f(|c){};
f :named(35); # A named argument (in "adverb" form.)
f named => 35; # Also a named argument.
f :35named; # A named argument using abbreviated adverb form
f 'named' => 35; # Not a named argument, a Pair in a positional argument
my \c = <a b c>.Capture;
f |c; # Merge the contents of Capture $c as if they were supplied
Arguments passed to a function are conceptually first collected in a
C<Capture> container. Details about the syntax and use of these
Expand All @@ -141,9 +141,10 @@ containers can be found in the L<documentation on the C<Capture> class|Capture>.
When using named arguments, note that normal List "pair-chaining" allows
one to skip commas between named arguments.
f :dest</tmp/foo> :src</tmp/bar> :lines(512)
f :32x :50y :110z # This flavor of "adverb" works, too
f :a:b:c # The spaces are also optional.
sub f(|c){};
f :dest</tmp/foo> :src</tmp/bar> :lines(512);
f :32x :50y :110z; # This flavor of "adverb" works, too
f :a:b:c; # The spaces are also optional.
=head2 Return values
Expand Down Expand Up @@ -237,17 +238,19 @@ arguments. Consider this basic example:
say "Hooray for your $reason, $name -- you got rank $rank!";
}
congratulate('being a cool number', 'Fred'); # OK
congratulate('being a cool number', 'Fred', 42); # OK
congratulate('being a cool number', 42); # Proto match error
=for code :skip-test
congratulate('being a cool number', 'Fred'); # OK
congratulate('being a cool number', 'Fred', 42); # OK
congratulate('being a cool number', 42); # Proto match error
All C<multi congratulate> will conform to the basic signature of two strings,
optionally followed by further parameters. The C<|> is an un-named C<Capture>
parameter, allowing a C<multi> which takes additional arguments. The third call
fails at compile time because the proto's C<signature> becomes the common
signature of all three, and C<42> doesn't match C<Str>.
say &congratulate.signature #-> (Str $reason, Str $name, | is raw)
=fod code :skip-test
say &congratulate.signature #-> (Str $reason, Str $name, | is raw)
You can give the C<proto> a function body, and place the C<{*}> where
you want the dispatch to be done.
Expand All @@ -266,10 +269,11 @@ you want the dispatch to be done.
C<{*}> always dispatches to candidates with the parameters it's called
with. Parameter defaults and type coercions will work but are not be passed on.
proto mistake-proto(Str() $str, Int $number = 42) {*}
multi mistake-proto($str, $number) { say $str.WHAT }
mistake-proto(7, 42); #-> (Int) -- coercions not passed on
mistake-proto('test'); #!> fails -- defaults not passed on
=for code :skip-test
proto mistake-proto(Str() $str, Int $number = 42) {*}
multi mistake-proto($str, $number) { say $str.WHAT }
mistake-proto(7, 42); #-> (Int) -- coercions not passed on
mistake-proto('test'); #!> fails -- defaults not passed on
=comment only
Expand Down Expand Up @@ -308,29 +312,32 @@ This can be achieved by using a slurpy with a C<+> or C<+@> instead of C<**>:
This results in the following behavior, which is known as the "single
argument rule" and is important to understand when invoking slurpy functions:
grab(1, 2); # grab 1 grab 2
grab((1, 2)); # grab 1 grab 2
grab($(1, 2)); # grab 1 2
grab((1, 2), 3); # grab 1 2 grab 3
=for code :skip-test
grab(1, 2); # grab 1 grab 2
grab((1, 2)); # grab 1 grab 2
grab($(1, 2)); # grab 1 2
grab((1, 2), 3); # grab 1 2 grab 3
This also makes user-requested flattening feel consistent whether there is
one sublist, or many:
grab(flat (1, 2), (3, 4)); # grab 1 grab 2 grab 3 grab 4
grab(flat $(1, 2), $(3, 4)); # grab 1 2 grab 3 4
grab(flat (1, 2)); # grab 1 grab 2
grab(flat $(1, 2)); # grab 1 2
=for code :skip-test
grab(flat (1, 2), (3, 4)); # grab 1 grab 2 grab 3 grab 4
grab(flat $(1, 2), $(3, 4)); # grab 1 2 grab 3 4
grab(flat (1, 2)); # grab 1 grab 2
grab(flat $(1, 2)); # grab 1 2
It is worth noting that mixing binding and sigilless variables
in these cases requires a bit of finesse, because there is no Scalar
intermediary used during binding.
my $a = (1, 2); # Normal assignment, equivalent to $(1, 2)
grab($a); # grab 1 2
my $b := (1, 2); # Binding, $b links directly to a bare (1, 2)
grab($b); # grab 1 grab 2
my \c = (1, 2); # Sigilless variables always bind, even with '='
grab(c); # grab 1 grab 2
=for code :skip-test
my $a = (1, 2); # Normal assignment, equivalent to $(1, 2)
grab($a); # grab 1 2
my $b := (1, 2); # Binding, $b links directly to a bare (1, 2)
grab($b); # grab 1 grab 2
my \c = (1, 2); # Sigilless variables always bind, even with '='
grab(c); # grab 1 grab 2
=head1 Functions are First-Class Objects
Expand All @@ -340,21 +347,17 @@ other object.
There are several ways to get hold of a code object. You can assign it to a
variable at the point of declaration:
=begin code
my $square = sub (Numeric $x) { $x * $x }
# and then use it:
say $square(6); # 36
=end code
my $square = sub (Numeric $x) { $x * $x }
# and then use it:
say $square(6); # 36
Or you can reference an existing named function by using the C<&> in front of
it.
=begin code
sub square($x) { $x * $x };
# get hold of a reference to the function:
my $func = &square
=end code
sub square($x) { $x * $x };
# get hold of a reference to the function:
my $func = &square
This is very useful for I<higher order functions>, that is, functions that
take other functions as input. A simple one is L<map|/type/List#routine_map>,
Expand All @@ -371,22 +374,20 @@ reference surrounded by C<[> and C<]>.
sub plus { $^a + $^b };
say 21 [&plus] 21;
OUTPUT«42␤»
# OUTPUT«42␤»
=head2 Closures
All code objects in Perl 6 are I<closures>, which means they can reference
lexical variables from an outer scope.
=begin code
sub generate-sub($x) {
my $y = 2 * $x;
return sub { say $y };
# ^^^^^^^^^^^^^^ inner sub, uses $y
}
my $generated = generate-sub(21);
$generated(); # 42
=end code
sub generate-sub($x) {
my $y = 2 * $x;
return sub { say $y };
# ^^^^^^^^^^^^^^ inner sub, uses $y
}
my $generated = generate-sub(21);
$generated(); # 42
Here C<$y> is a lexical variable inside C<generate-sub>, and the inner
subroutine that is returned uses it. By the time that the inner sub is called,
Expand Down Expand Up @@ -415,19 +416,17 @@ They carry additional functionality in addition to what L<Block|/type/Block>
supplies: they can come as L<multis|#Multi-dispatch>,
you can L<wrap|/type/Routine#method_wrap> them, and exit early with C<return>:
=begin code :allow<B>
my $keywords = set <if for unless while>;
sub has-keyword(*@words) {
for @words -> $word {
B<return> True if $word (elem) $keywords;
my $keywords = set <if for unless while>;
sub has-keyword(*@words) {
for @words -> $word {
return True if $word (elem) $keywords;
}
False;
}
False;
}
say has-keyword 'not', 'one', 'here'; # False
say has-keyword 'but', 'here', 'for'; # True
=end code
say has-keyword 'not', 'one', 'here'; # False
say has-keyword 'but', 'here', 'for'; # True
Here C<return> does not just leave the block inside which it was called, but
the whole routine. In general, blocks are transparent to C<return>, they
Expand Down Expand Up @@ -568,10 +567,6 @@ or as
1 + (2 + 3) # right associative
or as single call to an operator with three operands
infix:<+>(1, 2, 3); # list associative
For addition of real numbers, the distinction is somewhat moot, because C<+> is
L<mathematically associative|https://en.wikipedia.org/wiki/Associative_property>.
Expand Down Expand Up @@ -614,14 +609,15 @@ type, variable, routine, attribute, or other language object.
Examples of traits are:
class ChildClass is ParentClass { ... }
# ^^ trait, with argument ParentClass
has $.attrib is rw;
# ^^^^^ trait with name 'rw'
class SomeClass does AnotherRole { ... }
# ^^^^ trait
has $!another-attribute handles <close>;
# ^^^^^^^ trait
=for code :skip-test
class ChildClass is ParentClass { ... }
# ^^ trait, with argument ParentClass
has $.attrib is rw;
# ^^^^^ trait with name 'rw'
class SomeClass does AnotherRole { ... }
# ^^^^ trait
has $!another-attribute handles <close>;
# ^^^^^^^ trait
... and also C<is tighter>, C<is looser>, C<is equiv> and C<is assoc> from the previous
section.
Expand Down Expand Up @@ -659,47 +655,39 @@ chain with arguments of your own choice.
For example
=begin code
multi a(Any $x) {
say "Any $x";
return 5;
}
multi a(Int $x) {
say "Int $x";
my $res = callwith($x + 1);
say "Back in Int with $res";
}
a 1;
=end code
produces this output:
=begin code
Int 1
Any 2
Back in Int with 5
=end code
multi a(Any $x) {
say "Any $x";
return 5;
}
multi a(Int $x) {
say "Int $x";
my $res = callwith($x + 1);
say "Back in Int with $res";
}
# OUTPUT:
# a 1;
# Int 1
# Any 2
# Back in Int with 5
Here C<a 1> calls the most specific C<Int> candidate first, and C<callwith>
re-dispatches to the less specific C<Any> candidate.
Very often, a re-dispatch passes the same argument along that the caller
received, so there is a special routine for that: C<callsame>.
=begin code
multi a(Any $x) {
say "Any $x";
return 5;
}
multi a(Int $x) {
say "Int $x";
my $res = callsame;
say "Back in Int with $res";
}
a 1; # Int 1\n Any 1\n Back in Int with 5
=end code
multi a(Any $x) {
say "Any $x";
return 5;
}
multi a(Int $x) {
say "Int $x";
my $res = callsame;
say "Back in Int with $res";
}
a 1; # Int 1\n Any 1\n Back in Int with 5
Another common use case is to re-dispatch to the next routine in the chain,
and not do anything else afterwards. That's why we have C<nextwith> and
Expand Down Expand Up @@ -776,14 +764,13 @@ Coercion types can help you to have a specific type inside a routine, but
accept wider input. When the routine is called, the argument is automatically
converted to the narrower type.
=begin code
=for code :skip-test
sub double(Int(Cool) $x) {
2 * $x
}
say double '21'; # 42
say double Any; # Type check failed in binding $x; expected 'Cool' but got 'Any'
=end code
Here the C<Int> is the target type to which the argument will be coerced, and
C<Cool> is the type that the routine accepts as input.
Expand All @@ -794,24 +781,28 @@ to C<Int()>.
The coercion works simply by looking for a method with the same name
as the target type. So you can define coercions for your own types like so:
class MyModule::Foo {
has $.msg = "I'm a foo!";
=begin code :skip-test
class Bar {...}
method MyModule::Bar {
::('MyModule::Bar').new(:msg($.msg ~ ' But I am now Bar.'));
}
}
class Foo {
has $.msg = "I'm a foo!";
class MyModule::Bar {
has $.msg;
}
method Bar {
Bar.new(:msg($.msg ~ ' But I am now Bar.'));
}
}
sub print-bar(MyModule::Bar() $bar) {
say $bar.WHAT; # (Bar)
say $bar.msg; # I'm a foo! But I am now Bar.
}
class Bar {
has $.msg;
}
print-bar MyModule::Foo.new;
sub print-bar(Bar() $bar) {
say $bar.WHAT; # (Bar)
say $bar.msg; # I'm a foo! But I am now Bar.
}
print-bar Foo.new;
=end code
Coercion types are supposed to work wherever types work, but Rakudo
currently (2015.02) only implements them for subroutine parameters.
Expand Down

0 comments on commit 1606ce2

Please sign in to comment.