Virtual Reality

Simplicity Made Easy

The second task of last week’s Perl Weekly Challenge

was to list the dates of the last Friday in every month of a given year.

Many of the participants went to great lengths to create efficient and accurate solutions:

tracking the last day of each month, detecting leap years correctly,

working out formulas for the day of the month for a particular date,

managing the complex date arithmetic required.

But, given the powerful Date class built into Perl 6, most of those

admirable exertions were not actually necessary.

The entire task could be accomplished simply by walking through

from 1 January to 31 December of the given year, first checking

if each date is a Friday (i.e. the “day of the week” value is 5), and then

checking if the following Friday (i.e. the date exactly one week later)

happens to fall in a different month.

If both of those criteria are true, then we have a “last Friday of the month”,

so we simply print it.

In other words:

for$year,1,1) ..$year,12,31) -> $date {

if $ == 5

&& $date.later(:1week).month != $date.month {

say $date;



We don’t need to explicitly worry how long each month is, whether the year is a leap

year, or how to work out whether a given day is a Friday; the Date class takes

care of all that for us.

And that’s not luck; it’s entirely by design. Perl 6 has

a huge number of built-in datatypes like this;

they’re yet another kind of “right tool, right at hand”.

Of course, because Perl 6 is multiparadigm, there are plenty of other ways

to wrap a solution around the conveniences of the Date class,

depending on how you prefer to think about the world.

If you like pure functional solutions, write it like so:

say join "n",

grep { .later(:1week).month != .month },

grep { .day-of-week == 5 },$year,1,1) ..$year,12,31);

Or you’d prefer a (potentially) parallel pipeline,

then filter the sequence of dates through a series of

independent filters and processors:$year,1,1) ..$year,12,31)

==> grep( {.day-of-week == 5} )

==> grep( {.later(:1week).month != .month} )

==> join( "n" )

==> say();

Or you’d rather use a purely OO approach, just call the appropriate methods

on the list of dates:

($year,1,1) ..$year,12,31))

.grep( {.day-of-week == 5} )

.grep( {.later(:1week).month != .month} )

.join( "n" )


You could even write it as an old-school imperative Perl one-liner:

.say if .day-of-week == 5

&& .later(:1week).month != .month

for$year,1,1) ..$year,12,31);

So, whether you prefer an imperative, functional, object-oriented,

or pipelined approach, you can solve this problem simply and

cleanly. Because Perl 6 has the necessary built-in data types

to do the heavy lifting for you.


Read More

Related posts

Instagram is killing its creepy stalking feature, the Following tab

admin2 admin2

‘The Great Hack’: Netflix doc unpacks Cambridge Analytica, Trump, Brexit and democracy’s death

admin2 admin2

Application extension: pitch in Startup Battlefield at Disrupt Berlin

admin2 admin2

Leave a Reply