This is my response to the Perl Weekly Challenge #108.
Everything in Raku is an object, if you want it to be, so we can
use the MOP (Meta Object Protocol) WHERE
method:
#! /usr/bin/env raku
my $str = 'A';
my $int = 1299;
my @array = ;
say $str.WHERE;
say $int.WHERE;
say @array.WHERE;
Running it:
$ ./locate-memory
140431262794192
140431262853352
140431263477168
See
docs.raku.org/language/mop#WHERE
for more information about WHERE
(and MOP).
Note that the address is a single byte. Both values in the program require more than a byte, so the address is probably the location of an object (or container in Rakuesque) of constant size, which in turn contain the type (if any) and number of bytes to hold the value (or values, if a list or hash).
#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
my $str = 'A';
my $int = 1299;
my @array = qw/A 1299/;
say \$str;
say \$int;
say \@array;
Running it gives this result:
$ ./locate-memory-perl
SCALAR(0x55e24109b390)
SCALAR(0x55e24109b270)
ARRAY(0x55e24109b348)
The first part is the type of object we got a reference to (in UPPER CASE LETTERS, for good measure). Then we get the actual address, in parens, as a hexadecimal value.
The challenge asked for the location in memory, and the «SCALAR» and «ARRAY» labels must go away:
File: locate-memory-perl-hex
#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
my $str = 'A';
my $int = 1299;
my @array = qw/A 1299/;
say get_hex_value(\$str);
say get_hex_value(\$int);
say get_hex_value(\@array);
sub get_hex_value
{
my $string = shift;
$string =~ /(0x[a-f\d]+)/; # [1]
return $1;
}
[1] Note the regexp to get hold of the hexadecinal value.
Running it gives the addresses:
$ ./locate-memory-perl-hex
0x55ac8143d3a0
0x55ac8143d280
0x55ac8143d358
Still as hexadecimal values. Raku used decimal, so let us convert them to decimal.
The built-in hex
function gives a warning when used on large hexadecinal
values, as we have here. Using the «Math::BigInt» module solves this problem:
> say hex("0x55ac8143d358");
Hexadecimal number > 0xffffffff non-portable at ...
94199391441752
> say Math::BigInt->new("0x55ac8143d358");
94199391441752
Note that hex
gave us the correct result. On my pc at least...
#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Math::BigInt;
my $str = 'A';
my $int = 1299;
my @array = qw/A 1299/;
say get_int_value(\$str);
say get_int_value(\$int);
say get_int_value(\@array);
sub get_int_value
{
my $string = shift;
$string =~ /(0x[a-f\d]+)/;
return Math::BigInt->new($1);
}
Running it:
$ ./locate-memory-perl-bigint
94303839351760
94303839351472
94303839351712
Write a script to display top 10 Bell Numbers
. Please refer to
wikipedia page for
more informations.
B0: 1 as you can only have one partition of zero element set
B1: 1 as you can only have one partition of one element set {a}.
B2:
{a}{b}
{a,b}
B5:
{a}{b}{c}
{a,b}{c}
{a}{b,c}
{a,c}{b}
{a,b,c}
B15:
{a}{b}{c}{d}
{a,b,c,d}
{a,b}{c,d}
{a,c}{b,d}
{a,d}{b,c}
{a,b}{c}{d}
{a,c}{b}{d}
{a,d}{b}{c}
{b,c}{a}{d}
{b,d}{a}{c}
{c,d}{a}{b}
{a}{b,c,d}
{b}{a,c,d}
{c}{a,b,d}
{d}{a,b,c}
I assume that «top 10» should mean the first ten values in the seqeunce. (The top 10 highest values is impossible, as the sequence never ends.)
There are several ways of doing this, but I have chosen
to use gather
/take
to collect the values as I build up
the values in the trangle described in the «Triangle scheme for calculations» section
in the wikipedia article.
#! /usr/bin/env raku
unit sub MAIN ($count = 10);
my $bell-triangle := gather
{
take 1; # [1]
take 1; # [2]
my @triangle = ((1)); # [3]
my $row = 0;
loop
{
$row++; # [4]
my @prev = @triangle[$row-1].flat; # [5]
my @new = @prev[*-1]; # [6]
for ^@prev.elems -> $index # [7]
{
@new.push: @new[*-1] + @prev[$index]; # [8]
}
@triangle.push: @new; # [9]
take @new[*-1]; # [10]
}
}
say $bell-triangle[^$count]; # [11]
[1] The first value.
[2] The second value.
[3] The triangle so far.
[4] The first iteration in this infinite loop gives is row number 1.
[5] Get the previous row.
[6] The first value on the new row is the lasy on on the previous one.
[7] We are going to add as many items as we had on the previous row (but with different values).
[8] Take the value to the left, add the value right above it, and save the result.
[9] Add the new row to the tree.
[10] The new value is returned here.
[11] Compute and print the requested number of values.
See my Raku Gather,
I Take article or
docs.raku.org/syntax/gather take for more information about
gather
/take
.
Running it gives the first ten values (or more, if you want):
$ ./bell-triangle
(1 1 2 5 15 52 203 877 4140 21147)
$ ./bell-triangle 11
(1 1 2 5 15 52 203 877 4140 21147 115975)
$ ./bell-triangle 12
(1 1 2 5 15 52 203 877 4140 21147 115975 678570)
$ ./bell-triangle 13
(1 1 2 5 15 52 203 877 4140 21147 115975 678570 4213597)
$ ./bell-triangle 20
(1 1 2 5 15 52 203 877 4140 21147 115975 678570 4213597 27644437 190899322 \
1382958545 10480142147 82864869804 682076806159 5832742205057)
Looking good.
gather
/take
, but I have used say
and and explit
number of iterations in the loop instead:
File: bell-triangle-perl
#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
my $count = 10;
my $count = $ARGV[0] // 10;
say 1; exit if $count == 1;
say 1; exit if $count == 2;
my @first = (1);
my @triangle = (\@first); # [1]
my $row = 0;
while ($count-- > 0)
{
$row++;
my @prev = @{$triangle[$row-1]}; # [1a]
my @new = $prev[-1];
for my $index (0 .. @prev -1)
{
push(@new, $new[-1] + $prev[$index]);
}
push(@triangle, \@new);
say $new[-1];
}
[1] Perl does not support arrays of arrays, but we can store each row as a reference
to a row (with \
), and then dereference it again (with the
@{…}
Running it gives the same result as the Raku version, albeit with each value on a new line:
$ ./bell-triangle-perl
1
1
2
5
15
52
203
877
4140
21147
115975
678570
$ ./bell-triangle-perl 3
1
1
2
5
15
And that's it.