# Raku - Playing with Records - Part Three

Article Series

Playing with Records Related Articles.

Table of Content
Where to Discuss?

Local Group

### 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 {

# recursive unique
my @uniq = unique(@xcld);

# returned array
}
}``````

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`.

#### 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 { ... }``````
1. Producer: `start { ... }`
2. Consumer: `loop { ... }`

#### Producer and Consumer

We should prepare two functions:

1. One for `Producer` that `send` to `channel`,
2. And the other one for `Consumer` that `receive` from `channel`.

`Producer` that `send` to `channel`.

``````start {
@tags.map: -> \$tag { \$c.send: \$tag; }
\$c.send: Nil;
\$c.close;
}``````

`Consumer` that `get` from `channel`.

``````my \$item;
loop {
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)``````
1. Sender: `sub produce { ... }`
2. Receiver: `sub consume { ... }`
3. Program entry point.

#### Sender

`Producer` that `send` to `channel`.

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;
}``````

`Consumer` that `get` from `channel`.

Consider bundle into a function.

``````sub consume(\$c) {
my \$item;
my @tags = ();

loop {
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 ].