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 Date.new($year,1,1) .. Date.new($year,12,31) -> $date {

if $date.day-of-week == 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 },

Date.new($year,1,1) .. Date.new($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:

Date.new($year,1,1) .. Date.new($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:

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

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

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

.join( "n" )

.say;

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

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

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

for Date.new($year,1,1) .. Date.new($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.

Damian

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