Abundantly
First Class

with Raku

by Arne Sommer

Abundantly First Class with Raku

[190] Published 3. July 2022.

This is my response to The Weekly Challenge #171.

Challenge #171.1: Abundant Number

Write a script to generate first 20 Abundant Odd Numbers.

According to wikipedia,

A number n for which the sum of divisors σ(n) > 2n, or, equivalently, the sum of proper divisors (or aliquot sum) s(n) > n.

For example, 945 is the first Abundant Odd Number.

Sum of divisors:
1 + 3 + 5 + 7 + 9 + 15 + 21 + 27 + 35 + 45 + 63 + 105 + 135 + 189 + 315
 = 975
File: abundant-number
#! /usr/bin/env raku

unit sub MAIN (Int :c(:$count) where $count > 0 = 20, :v(:$verbose));  # [1]

my $abundant := (1 .. Inf).grep( *.&is-abundant );                     # [2]

say $abundant[^$count].join(", ");                                     # [3]

sub divisors ($number, :$not-self, :$not-one)                          # [4]
{
  my @divisors;
  
  for ($not-one ?? 2 !! 1) .. $number/2 -> $candidate
  {
    @divisors.push: $candidate if $number %% $candidate;
  }
  
  @divisors.push: $number unless $not-self;
  say ": $number -> @divisors[] = { @divisors.sum }" if $verbose;  
  return @divisors;
}

sub is-abundant ($number)                                             # [5]
{
  return $number % 2 && divisors($number, :not-self).sum > $number;   # [6]
  # return $number % 2 && divisors($number).sum > $number * 2;        # [7]
}

[1] Specify another number of values to print, if the default 20 does not suit you.

[2] Start with all the integers, and use grep to get only those that we want. Note the special .& calling syntax allowing us to pretend that a procedure is a method.

See docs.raku.org/language/operators#methodop_.& for more information about the special procedure invocation syntax .&.

[3] Print the required number of values from the sequence.

[4] This procedure should be familiar by now. See the second half of An Abundance of Numbers with Raku and Perl for details.

[5] Is the number abundant?

[6] Using the «Proper divisors» definition.

[7] Or you can use the «Divisors» definition.

Running it:

$ ./abundant-number
945, 1575, 2205, 2835, 3465, 4095, 4725, 5355, 5775, 5985, 6435, 6615, 6825, \
  7245, 7425, 7875, 8085, 8415, 8505, 8925

Looking good.

You can use verbose mode to check the result manually, if you are so inclined. Here is a selection of the output:

$ ./abundant-number -v -c=1
: 1 ->  = 0
: 3 -> 1 = 1
: 5 -> 1 = 1
: 7 -> 1 = 1
: 9 -> 1 3 = 4
: 11 -> 1 = 1
: 13 -> 1 = 1
…
: 935 -> 1 5 11 17 55 85 187 = 361
: 937 -> 1 = 1
: 939 -> 1 3 313 = 317
: 941 -> 1 = 1
: 943 -> 1 23 41 = 65
: 945 -> 1 3 5 7 9 15 21 27 35 45 63 105 135 189 315 = 975
945

Challenge #171.2: First-class Function

Create sub compose($f, $g) which takes in two parameters $f and $g as subroutine refs and returns subroutine ref i.e. compose($f, $g)->($x) = $f->($g->($x)).

e.g.
$f = (one or more parameters function)
$g = (one or more parameters function)

$h = compose($f, $g)
$f->($g->($x,$y, ..)) == $h->($x, $y, ..) for any $x, $y, ...

Let us start with the f and g functions:

File: first-class-function (partial)
#! /usr/bin/env raku

my $f = sub f ($val)   # [1]
{
  return $val * 10;
}

my $g = sub g ($val)   # [1]
{
  return $val + 1;
}

[1] Two ordinary procedures, with one input value and one (deterministic) output value. The trick (so to speak) is the fact that the sub keyword returns a reference to the procedure, and we assign that value to a variable for each one.

See docs.raku.org/syntax/sub more information about sub.

Call Me

If you want to call a function, you can either use the name (i.e. the normal way):

my $b = f(12);

Or the reference (if you have one):

my $b = $f(12);

The «compose» procedure is easy:

File: first-class-function (partial)
sub compose(&f, &g)     # [2]
{
  return sub ($arg)     # [3]
  {
    &f(&g($arg));       # [4]
  };
}

[2] The procedure takes two arguments, of the callable type (courtesy of the & (Callable) sigil). Calling it with other argument types will fail. The generic $ sigil works just fine, but without the Callable check.

[3] An anonymous procedure (i.e. without name), taking one input parameter (in $arg). The return value is a reference to this procedure.

[4] The procedure itself will - when executed - call the inner procedure &g($arg) first, and then the outer &f with the return value of the inner one.

And finally, executing the code:

File: first-class-function (the rest)
my $h = compose($f, $g);  # [5]

say $h(12);               # [6]
say $h(13);               # [7]

my $m = compose($g, $f);  # [8]

say $m(12);               # [9]
say $m(13);

[5] Feel free to use the & (Callable) sigil here (i.e. &h instead of $h), if that makes you feel better.

[6] Call the procedure(s).

[7] Ditto, with another input value.

[8] Changing the order of the procedures does matter.

[9] The same procedures, reordered, and the same input - but a different result.

Running it:

File: first-class-function (partial)
$ ./first-class-function
130
140
121
131

Looking good.

And that's it.