Preface
Goal: Continue Part Two
6: Approach in Solving Unique
A custom example, that you can rewrite.
An Algorithm Case
Why reinvent the wheel?
The same reason as any other articles.
x:xs Pattern Matching
The same with any other articles as well.
Exclude Function
The exclude
function is just a filter
with below details:
#!/usr/bin/raku
my @tags = ('rock',
'jazz', 'rock', 'pop', 'pop');
sub exclude($value, @tags) {
@tags.grep(none /$value/);
}
join(':', exclude('rock', @tags)).say;
With the result as below array
:
❯ ./21-exclude.raku
jazz:pop:pop
Recursive Unique Function
With exclude
function above,
we can build unique
function recursively.
Since we are going to reuse the unique approach in other script. It is better to bundle the script in its own raku module.
unit module MyHelperUnique;
sub unique(@tags) is export {
if (@tags <= 1) {
@tags;
} else {
# array[$head:@tail]
my ($head, @tail) = @tags;
# recursive unique
my @xcld = @tail.grep(none /$head/);
my @uniq = unique(@xcld);
# returned array
@uniq.unshift: $head;
}
}
The return values is in array.
Using Unique Module
There is nothing to say in this code below.
Just apply unique
function to our song records.
use MyHelperUnique;
my @tags = ('rock',
'jazz', 'rock', 'pop', 'pop');
say join(':', unique(@tags));
With the result as below array
:
❯ ./22-unique-a.raku
rock:jazz:pop
Applying Unique to Songs Records
Now we can apply the method to our unique song challenge.
#!/usr/bin/raku
use lib $*PROGRAM.dirname;
use MySongs;
use MyHelperFlatten;
use MyHelperUnique;
say join(':', unique(flatten(@songs)));
With the same result as below
❯ ./22-unique-b.raku
60s:jazz:rock:70s:pop
7: Generator
Yield
With procedural approach, we can also achieve the same thing.
We are going to consider this approach for concurrency topic.
Gather Take
Consider this function.
sub produce(@songs) {
gather for (@songs) {
@( %$_<tags> ).Slip.map: *.take
if ('tags' ∈ %$_.keys);
}}
Entry Point
Then we can call later:
# main: entry point
use lib $*PROGRAM.dirname;
use MySongs;
join(":", produce(@songs).unique).say;
With the result of
❯ ./25-gather.raku
60s:jazz:rock:70s:pop
8: Concurrency with Channel
Raku
support Actor Model
pattern.
We can rewrite previous process through channel
,
using sender
and receiver
.
Reference
The Simple Skeleton
We should be ready for the simple demo. This is only consist of one short file.
#!/usr/bin/raku
my $c = Channel.new;
my @tags = ('rock',
'jazz', 'rock', 'pop', 'pop');
start { ... }
loop { ... }
- Producer:
start { ... }
- Consumer:
loop { ... }
Producer and Consumer
We should prepare two functions:
- One for
Producer
thatsend
tochannel
, - And the other one for
Consumer
thatreceive
fromchannel
.
Producer
thatsend
tochannel
.
start {
@tags.map: -> $tag { $c.send: $tag; }
$c.send: Nil;
$c.close;
}
Consumer
thatget
fromchannel
.
my $item;
loop {
$item = $c.receive;
if ($item) {
$item.say;
} else {
last;
}
}
Running Both Routine
The result will be as below list
:
❯ ./31-channel.raku
rock
jazz
rock
pop
pop
Real Skeleton
How about the real demo. This is also consist only one short file.
#!/usr/bin/raku
sub produce($c, @songs) { ... }
sub consume($c) { ... }
# main: entry point
...
start { produce($chan, @songs); }
consume($chan)
- Sender:
sub produce { ... }
- Receiver:
sub consume { ... }
- Program entry point.
Sender
Producer
thatsend
tochannel
.
Consider bundle into a function.
sub produce($c, @songs) {
for (@songs) {
if ('tags' ∈ %$_.keys) {
@( %$_<tags> ).Slip
.map: -> $tag { $c.send: $tag; }
next; # dummy
}
}
$c.send: Nil;
$c.close;
}
Receiver
Consumer
thatget
fromchannel
.
Consider bundle into a function.
sub consume($c) {
my $item;
my @tags = ();
loop {
$item = $c.receive;
if ($item) {
@tags.push: $item;
} else {
join(":", @tags.unique).say;
last;
}
}
}
Running Both Routine
Pretty short entry point right?
No need to bundle into function.
# main: entry point
use lib $*PROGRAM.dirname;
use MySongs;
my $chan = Channel.new;
start { produce($chan, @songs); }
consume($chan)
Result
The result will be as below list
:
❯ ./32-channel.raku
60s:jazz:rock:70s:pop
This is the end of our raku
journey in this article.
We shall meet again in other article.
What is Next 🤔?
Consider continue reading [ TCL - Playing with Records - Part One ].