with Raku and Perl

This is my response to the Perl Weekly Challenge #146.

Write a script to generate the

File: 10001st
`10001st`

prime number.
#! /usr/bin/env raku
unit sub MAIN (Int :$number where $number > 0 = 10001); # [1]
my $primes := (1..Inf).grep( *.is-prime ); # [2]
say $primes[$number -1]; # [3]

[1] You can optionally specify another index than 1001.

See
docs.raku.org/routine/is-prime
for more information about `is-prime`

.

[3] Print the requested prime (with an index one less than the number, as the index is zero based).

Running it:

$ ./10001st
104743

You can get any prime you want (by index):

$ ./10001st -number=1
2
$ ./10001st -number=2
3
$ ./10001st -number=3
5
$ ./10001st -number=43
191

#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Math::Prime::Util 'is_prime'; # [1]
my $number = int($ARGV[0] || 10001);
my $count = 0;
my $candidate = 0;
while (++$candidate)
{
next unless is_prime($candidate);
$count++;
last if $count == $number;
}
say $candidate;

[1] Perl does not have a built in function for prime recognition, but the «Math::Prime::Util» module supplies one for us.

Running it gives the same result as the Raku version:

$ ./10001st-perl
104743
$ ./10001st-perl 43
191

Consider the following

You are given a fraction, member of the tree created similar to the above sample.

Write a script to find out the parent and grandparent of the given member.

Example 1:

`Curious Fraction Tree`

:
You are given a fraction, member of the tree created similar to the above sample.

Write a script to find out the parent and grandparent of the given member.

Example 1:

Input: $member = '3/5';
Output: parent = '3/2' and grandparent = '1/2'

Example 2:
Input: $member = '4/3';
Output: parent = '1/3' and grandparent = '1/2'

File: cft.dot

digraph foogrph {
"1/3" -> "1/4";
"1/3" -> "4/3";
"3/2" -> "3/5";
"3/2" -> "5/2";
"1/2" -> "1/3";
"1/2" -> "3/2";
"2/3" -> "2/5";
"2/3" -> "5/3";
"3/1" -> "3/4";
"3/1" -> "5/1";
"2/1" -> "2/3";
"2/1" -> "3/1";
"1/1" -> "1/2";
"1/1" -> "2/1";
}

Then I used the «dot» command to get the svg file:

dot -Tsvg cft.dot > cft.svg

See e.g. my Pokemon Chiao, Raku article for more information about Graphviz.

We can hard code the data structure, just as I did with the graph above (except that the relationship is «child -> parent», and not «parent -> child» as in the graph):

File: cft-hash#! /usr/bin/env raku
subset NuDe of Str where * ~~ /^\d+\/\d+$/; # [1]
unit sub MAIN (NuDe $fraction); # [1]
my %parent = ( '1/4' => '1/3',
'4/3' => '1/3',
'3/5' => '3/2',
'5/2' => '3/2',
'1/3' => '1/2',
'3/2' => '1/2',
'2/5' => '2/3',
'5/3' => '2/3',
'3/4' => '3/1',
'4/1' => '3/1',
'2/3' => '2/1',
'3/1' => '2/1',
'1/2' => '1/1',
'2/1' => '1/1'
);
my $parent = %parent{$fraction} // die "No such member: $fraction"; # [2]
my $grandparent = %parent{$parent} // die "No such member: $parent"; # [2]
say "parent = \'$parent\' and grandparent = \'$grandparent\'"; # [3]

[1] A custom type for the fraction (as a string). Nu = Numerator, De = Denominator.

[2] Get the parent and grandparent, if they are in the hash.

[3] Print the result.

Running it:

$ ./cft-hash '3/5'
parent = '3/2' and grandparent = '1/2'
$ ./cft-hash '4/3'
parent = '1/3' and grandparent = '1/2'

Not very exciting, but it works.

Note that the program will fail if we give it a fraction that we have not put in, as e.g.
`1/5`

:

$ ./cft-hash '1/5'
No such member: 1/5
in sub MAIN at ./cft-hash line 21

Let us find the pattern, i.e. how to get from a fraction to the parent, and use that to compute the parent and grandparent values on the spot.

File: cft#! /usr/bin/env raku
subset NuDe of Str where * ~~ /^\d+\/\d+$/;
unit sub MAIN (NuDe $fraction);
my $parent = parent($fraction);
my $grandparent = parent($parent);
say "parent = \'$parent\' and grandparent = \'$grandparent\'";
sub parent (NuDe $fraction) # [1]
{
my (Int $numerator, Int $denominator) = $fraction.split("/")>>.Int; # [2]
return "0/0" if $numerator == $denominator == 1; # [3]
$numerator < $denominator # [4]
?? return $numerator ~ "/" ~ $denominator - $numerator # [4a]
!! return $numerator - $denominator ~ "/" ~ $denominator; # [4b]
}

[1] This procedure gives us the value of the parent.

[2] Split the fraction (a string) into the integers. The `>>.Int`

coercer is there as we want integers values and not strings, as is the default when
we split strings. We want this coersion as the variables require integer values,
by design.

[3] If we are at the top of the tree, return "0/0". Another possibility is to die, i.e. giving up.

[4] The formulae for the parent differ for left and right child nodes. We decide which one we have by comparing the numerator and denominator. The formulae [4a and 4b] are reversed engineered from the tree.

Running it:

$ ./cft '3/5'
parent = '3/2' and grandparent = '1/2'
$ ./cft '4/3'
parent = '1/3' and grandparent = '1/2'
$ ./cft '11/8'
parent = '3/8' and grandparent = '3/5'

We got the right result.

Here is a program that generates the «dot» file, with as many levels as you want:

File: mkcft

#! /usr/bin/env raku
subset NuDe of Str where * ~~ /^\d+\/\d+$/;
unit sub MAIN (Int $levels where $levels > 0 = 3);
say 'digraph foogrph {';
recurse('1/1');
say '}';
sub recurse (NuDe $current, $level = 1)
{
my $left = left-child($current);
my $right = right-child($current);
say " \"{ $current }\" -> \"{ left-child($current) }\"";
say " \"{ $current }\" -> \"{ right-child($current) }\"";
return if $level == $levels;
recurse($left, $level +1);
recurse($right, $level +1);
}
sub left-child (NuDe $fraction)
{
my (Int $numerator, Int $denominator) = $fraction.split("/")>>.Int;
return "$numerator/{ $numerator + $denominator }";
}
sub right-child (NuDe $fraction)
{
my (Int $numerator, Int $denominator) = $fraction.split("/")>>.Int;
return "{ $numerator + $denominator }/$denominator";
}

The original 3 level graph looks the same. Here is the 4 level one:

$ ./mkcft 4 > 4.dot
$ dot -Tsvg 4.dot > 4.svg

The 5 level one:

$ ./mkcft 5 > 5.dot
$ dot -Tsvg 5.dot > 5.svg

The order (left to right) is as expected, as we specified (printed) them in the correct order (left before right), for each row (or level). Screw up the order, and things will behave differently. (Crossing dependencies will cause Graphwiz to rearrange the graph so that as few dependency lines as possible intersect, but that is not an issue here.)

#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use feature 'signatures';
no warnings qw(experimental::signatures);
my $fraction = $ARGV[0] // "";
die "Not a fraction: $fraction" unless $fraction =~ /^\d+\/\d+$/;
my $parent = parent($fraction);
my $grandparent = parent($parent);
say "parent = \'$parent\' and grandparent = \'$grandparent\'";
sub parent ($fraction)
{
my ($numerator, $denominator) = split("/", $fraction);
return "0/0" if $numerator == 1 && $denominator == 1;
$numerator < $denominator
? return $numerator . "/" . ( $denominator - $numerator )
: return ($numerator - $denominator ) . "/" . $denominator;
}

Running it gives the same result as the Raku version:

$ ./cft-perl '3/5'
parent = '3/2' and grandparent = '1/2'
$ ./cft-perl '4/3'
parent = '1/3' and grandparent = '1/2'
$ ./cft-perl '11/8'
parent = '3/8' and grandparent = '3/5'

And that's it.