Home > Raku > Swarming Sundays

Swarming Sundays

To not miss any Sundays, PWC 175 is asking us to find them. Raku helps us a great deal, because we can easily find the last day in a month, calculate it’s distance to the next Sunday and turn the clock back by that many days.

for 2022 -> $year {
    for 1..12 -> $month {
        my $last-day-in-month = Date.new($year, $month, *);
        my $Δsunday = $last-day-in-month.day-of-week % 7;
        say $last-day-in-month.earlier(:days($Δsunday));
    }
}

If you follow this blog, you will have spotted my distaste for simple loops. They get in the way of using interesting language features and thus fun. Date.new will only ever return a single date. With an Array of dates I could use vector operations to calculate all last Sundays in a month in one go. So I need a way to create a swarm of Dates, depending on a pattern. Signatures are patterns (and just fancy lists), so let’s use those.

sub swarm(::Type, @sig is copy, Range $range) {
    my $var;
    my $marker-index = @sig.first([], :k);
    @sig[$marker-index] := $var;
    gather for @$range {
        $var = $_;
        take Type.new: |@sig;
    }
}

my @months = swarm(Date, (2022, @, *), 1..12);
my @Δsunday = @months».day-of-week »%» 7;
.say for @months.map({ .earlier(:days(@Δsunday.shift)) });

The sub swarm takes a type, a parameter-list meant to be used on that types’ new method and a range. It finds the empty list created by @ and replaced it with a container. That container is then filled with a value taken from the range. This is as neat as it is unnecessary. Raku will do the whole shebang for us if we use a Junction. Getting hold of the results requires a module by lizmat.

use eigenstates;

my @months = Date.new(2022, (1..12).any, *).&eigenstates;
my @Δsunday = @months».day-of-week »%» 7;
.say for @months.map({ .earlier(:days(@Δsunday.shift)) });

# OUTPUT: No such method 'List' for invocant of type 'BOOTArray'.  Found 'List'
on type 'Any'
  in sub eigenstates at /usr/local/src/rakudo/install/share/perl6/site/sources/EDAA4AE0C8813633A2EA392374FB72F6B4D61047 (eigenstates) line 4

Thank you MoarVM, for creating a nice BOOTArray for us that we can’t easily turn into a List. Some bewilderment and a PR later, the result changed. You may wish to zef upgrade if you use eigenstates.

2022-01-30
2022-02-27
2022-03-27
2022-04-24
2022-05-29
2022-06-26
2022-07-31
2022-08-28
2022-09-25
2022-10-30
2022-11-27
2022-12-25

Just displaying those Sundays wont justify getting rid of the loop. If we need that in an API, returning a list of Dates without much hassle seems valuable. Please note, that the BOOTArray indicates eagerness and I don’t think it has to be. Junctions might get lazier and faster in the future.

Categories: Raku