Skip to content

Instantly share code, notes, and snippets.

@masak
Created July 22, 2010 10:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save masak/485816 to your computer and use it in GitHub Desktop.
Save masak/485816 to your computer and use it in GitHub Desktop.
== Perl 6 has six built-ins you never knew you needed: try them in Rakudo Star
=== .pick
say @deck.pick(); # pick a card, any card...
say @deck.pick(5); # poker hand
my @shuffled = @deck.pick(*); # here, '*' means 'keep going'
my @urn = <black white white>; # beads, 1/3 black, 2/3 white
.say for @urn.pick(50, :replace); # put back after each pick
for @urn.pick(*, :replace) {
.say; # infinite bead picker
}
say [+] (1..6).pick(4, :replace); # 4d6
class Enemy {
method attack-with-arrows { say "peow peow peow" }
method attack-with-swords { say "swish cling clang" }
method attack-with-fireball { say "sssSSS fwoooof" }
method attack-with-camelia { say "flap flap RAWWR!" }
}
my $selector = { .name ~~ /^ 'attack-with-' / };
given Enemy.new -> $e {
my $attack-strategy
= $e.^methods().grep($selector).pick();
$e.$attack-strategy; # call a random method
}
=== .classify
my @names = <Patrick Jonathan Larry Moritz Audrey>;
say .key, "\t", ~.values
for @names.classify( *.chars );
# Output:
# 5 Larry
# 6 Moritz Audrey
# 7 Patrick
# 8 Jonathan
.say for slurp("README")\ # whole file into string
.words()\ # split into list of words
.classify( *.Str )\ # group words w/ multiplicity
.map({; .key => .value.elems })\
# turn lists into lengths
.sort( { -.value } )\ # sort descending
.[ ^10 ]; # 10 most common words
class Student {
has Str $.name;
has Int $.grade is rw;
}
my Student @students = get-students();
for @students.classify( *.grade ).sort -> $group {
say "These students got grade $group.key():";
say .name for $group.value.list;
}
=== .sort
# 1 if $a is higher, -1 if $b is higher, 0 if equal
$a <=> $b;
# sort students according to grade
@students.sort: -> $a, $b { $a.grade <=> $b.grade };
# same thing
@students.sort: { $^a.grade <=> $^b.grade };
# same thing
@students.sort: { .grade };
# same thing
@students.sort: *.grade;
# leg gives -1, 0 or 1 according to lexicographic ordering
# 'leg' is for Str, 'cmp' is now for type-agnostic sort
$a leg $b;
# sort students by name (Unicode order)
@students.sort: { $^a.name leg $^b.name };
# same thing
@students.sort: *.name;
# don't worry, things are properly cached; no re-evaluations
@items.sort: *.expensive-calculation();
# ...which means this works (and is a fair shuffle)
@deck.sort: { rand }
# ...but this is cuter :)
@deck.pick(*);
=== Operator overloading
sub infix:<±>($number, $fuzz) {
$number - $fuzz + rand * 2 * $fuzz;
}
say 15 ± 5; # somewhere between 10 and 20
sub postfix:<!>($n) { [*] 1..$n }
say 5!; # 120
class Physical::Unit {
has Int $.kg = 0; # these attrs denote powers of units
has Int $.m = 0; # eg $.kg == 2 means that this object
has Int $.s = 0; # has a kg**2 unit
has Numeric $.payload;
method multiply(Physical::Unit $other) {
Physical::Unit.new(
:kg( $.kg + $other.kg ),
:m( $.m + $other.m ),
:s( $.s + $other.s ),
:payload( $.payload * $other.payload )
)
}
method invert() {
Physical::Unit.new(
:kg( -$.kg ), :m( -$.m ), :s( -$.s ),
:payload( 1 / $.payload )
)
}
method Str {
$.payload
~ ($.kg ?? ($.kg == 1 ?? " kg" !! "kg**$.kg") !! "")
~ ($.m ?? ($.m == 1 ?? " m" !! "m**$.m") !! "")
~ ($.s ?? ($.s == 1 ?? " s" !! "s**$.s") !! "")
}
}
sub postfix:<kg>(Numeric $payload) { Physical::Unit.new( :kg(1), :$payload ) }
sub postfix:<m>(Numeric $payload) { Physical::Unit.new( :m(1), :$payload ) }
sub postfix:<s>(Numeric $payload) { Physical::Unit.new( :s(1), :$payload ) }
# Note how we now use 'multi sub', so as not to shadow the original infix:<*>
multi sub infix:<*>(Physical::Unit $a, $b) {
$a.clone( :payload($a.payload * $b) );
}
multi sub infix:<*>($a, Physical::Unit $b) {
$b.clone( :payload($a * $b.payload) );
}
multi sub infix:<*>(Physical::Unit $a, Physical::Unit $b) {
$a.multiply($b);
}
multi sub infix:</>(Physical::Unit $a, $b) {
$a.clone( :payload($a.payload / $b) );
}
multi sub infix:</>($a, Physical::Unit $b) {
$b.invert.clone( :payload($a / $b.payload) );
}
multi sub infix:</>(Physical::Unit $a, Physical::Unit $b) {
$a.multiply($b.invert);
}
say 5m / 2s; # 2.5 m s**-1
say 100kg * 2m / 5s; # 40 kg m s**-1
=== infix:<Z>
# Z (the 'zip operator') means "mix these lists together"
my @tastes = <spicy sweet bland>;
my @foods = <soup potatoes tofu>;
@tastes Z @foods; # <spicy soup sweet potatoes bland tofu>
# » means "call the method for each element"
.say for @students».grade; # all the grades
for @students».name Z @students».grade -> $name, $grade {
say "$name got a $grade this year";
}
# Note that the latter list is infinite -- it works anyway
for @students».name Z (1..6).pick(*, :replace) -> $name, $roll {
say "$name rolls a $roll";
}
# you can also Z together two lists with an infix op
my @total-scores = @first-scores Z+ @second-scores;
# strings as keys, the appropriate number of 1s as values
my %hash = @names Z=> 1 xx *; # xx is list repeat
# line people up with increasing numbers
my %people2numbers = @people Z=> 1..*;
# don't have a good op? roll your own!
sub infix:<likes>($liker, $likee) { "$liker is fond of $likee" }
# note how the op infix:<Zlikes> is automatically available
my @relations = @likers Zlikes @likees;
=== infix:<...>
1 ... $n # integers 1 to $n
$n ... 1 # and backwards
1, 3 ... $n # odd numbers to $n
1, 3, ... * # odd numbers
1, 2, 4 ... * # powers of two
map { $_ * $_ }, 1 ... * # squares
1, 1, -> $a, $b { $a + $b } ... * # fibonacci
1, 1, { $^a + $^b } ... * # ditto
1, 1, *+* ... * # ditto
'Camelia', *.chop ... ''; # all prefixes of 'Camelia'
# See http://blog.plover.com/CS/parentheses.html
# for the principle behind this
sub next-balanced-paren-string($s) {
$s ~~ /^ ( '('+ ) ( ')'+ ) '(' /;
[~] $s.substr(0, $/.from),
"()" x ($1.chars - 1),
"(" x ($0.chars - $1.chars + 2),
")",
$s.substr($/.to);
}
my $N = 3;
my $start = "()" x $N;
my &step = &next-balanced-paren-string;
my $end = "(" x $N ~ ")" x $N;
for $start, &step ... $end -> $string {
say $string;
}
# Output:
# ()()()
# (())()
# ()(())
# (()())
# ((()))
Rakudo Star releases in a week, July 29th.
@baest
Copy link

baest commented Jul 22, 2010

What about this one:
subset Positive of Int where { $_ > 0 }; sub postfix:<!> (Positive $n) { [*] 1 .. $n } ; say 10!;

I think it really shows a lot of strengths in Perl 6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment