🎄 26/25. Overview of the Perl 6 One-Liner Advent Calendar 2018

The Perl 6 One-Liner Advent Calendar 2018 is over! Let’s make a quick overview of what we have covered so far. There were a few themes covered.

First, some one-liners from the Perl 6 Calendar 2019 were explained in more detail. We looked at how to generate random passwords and random integers, how to print current date, and at how good Perl 6 is doing with Unicode.

Second, a number of problems from Project Euler were solved in Perl 6: #1 grepping dividable numbers, #2 adding up even Fibonacci numbers, #4 testing palindromic numbers, #5 finding the least common divider, #7 printing the given Fibonacci number, #13 computing a sum of big numbers, #19 counting Sundays and counting them differently, #25 finding a Fibonacci number of the given length, and #34 finding a sum of the numbers that are equal to the sum of factorials of their digits.

Third, we looked at some isolated elements of Perl 6 syntax, such as meta-operator X, range and sequence operators, reduction operator, or how rational numbers work in Perl 6 and how to use complex number in geometry. A numerous times, we were using the built-in routines map and grep, and the WhateverCode objects.

Fourth, we explored a few common sequences: Fibonacci numbers and prime numbers, or the Leibnitz series for computing the value of π.

Fifth, we solved a few golf problems: how to print the first Fibonacci numbers, or how to print the first prime numbers. A separate post was dedicated to the ideas of how to make the code more compact.

Sixth, we moved on to command-line tools, covered the basic options that Rakudo supports and created a few one-liners for manipulating files, such as the one for renaming a bunch of files, or reversing a text file, or merging two files horizontally, or computing totals from the table columns, or how to read from multiple input files.

As a bonus, the posts from the One-Liner calendar have been translated to Chines, thanks to Chen Yf (if I decoded the name correctly).

Also, don’t forget about my article in the regular Perl 6 Advent Calendar about how to make the grammar more compact.

🎄 25/25. Tips and ideas for the Perl 6 Golf code

Welcome to Day 25, the last day of the Perl 6 One-Liner Advent Calendar! Traditional advent calendars have only 24 entries, and our bonus post today will be dedicated to some tips and tricks that you can use in Perl 6 golf contest.

There is a great site, code-golf.io, where you can try solving a number of problems, and move Perl 6 to the top scores. I suspect that many problems can benefit from the techniques that were covered in the previous days of this One-Liner Advent Calendar.

Omitting topic variable

If methods are called on the topic variable $_, then the name of the variable is not really needed for Perl 6 to understand what you are talking about, so, avoid explicitly naming the topic variable:

$_.say for 1..10

Using ranges for making loops

Ranges in Perl are great things to express loop details: in a few characters, you specify both the initial and final state of the loop variable. Postfix forms are usually shorter.

for 1..10 {.say}
.say for 1..10

Think if you can count from 0, in which case, a caret character can be used to get a range starting from 0. The following code prints the numbers 0 to 9:

.say for ^10

Choosing between a range and a sequence

In loops, sequences can work exactly the same as a range would do. The choice may depend on whether the Golf software counts bytes or Unicode characters. In the first case, the two dots of a range are preferable over the three dots of a range. In the second case, use a Unicode character:

.say for 1..10
.say for 1...10
.say for 1…10

When you need to count downwards, sequences are your friends, as they can deduce the direction of changing the loop counter:

.say for 10…1

Using map instead of a loop

In some cases, especially when you have to make more than one action with the loop variable, try using map to iterate over all the values:

(^10).map: *.say

Omitting parentheses

Unlike Perl 5, Perl 6 does not force you to use parentheses in condition checks in the regular form:

if ($x > 0) {say $x;exit}
if $x > 0 {say $x;exit}

Sometimes, you will want to omit parentheses in function calls, too.

Neither you need parentheses when declaring arrays or hashes. With arrays, use the quoting construct on top of that:

my @a = ('alpha', 'beta')
my @b=<alpha beta>

Using chained comparisons

Another interesting feature is using more than one condition in a single expression:

 say $z if $x < 10 < $y

Choosing between methods and functions

In many cases, you can choose between calling a function and using a method. Method calls can be additionally chained after each other, so you can save a lot of parentheses or spaces:

(^10).map({.sin}).grep: *>0 

When there exist both a method and a stand-alone function, method call is often shorter or at least the same length if you omit parentheses.

abs $x

Using Unicode characters

Perl 6 operators often have Unicode equivalents, where you can express a wordy construct with a single character. Compare:

if $x=~=$y
if $x≅$y

Built-in constants are also available in the Unicode space, for example, pi vs π, or Inf vs .

There are many numbers, both small and big, that can be replaced with a single Unicode symbol: 1/3 vs , or 20 vs , or 100 vs .

Using superscripts

Superscripts are great for calculating powers. Compare:

say $x**2

Using \ to make sigilless variables

Don’t forget about the the following way of binding containers and creating a kind of a sigilless variable:

my \a=42;say a

Using default parameters

When you are working with functions or class methods, check if there are default values in their signatures. Also check if there is an alternative variant with positional arguments. Compare, for example, three ways of creating a date object.


Using && instead of if

Boolean expressions can save a few characters, as Perl will not calculate the second condition if the first gives the result already. For example:

.say if $x>0   

Choosing between put vs say

Finally, sometimes it is better to use put instead of say. In some cases, you will be free from parentheses in the output when printing arrays, for example. In some other cases you will get all values instead of concise output when working with ranges, for example:

> say 1..10
> put 1..10
1 2 3 4 5 6 7 8 9 10

Till next year!

You can also find many interesting ideas in the last year’s advent post by Aleks-Daniel Jakimenko-Aleksejev.

But this time, this Perl 6 One-Line Advent Calendar is completely over. There will be one more post with an overview of everything published in the last 25 days.

I wish you all the best with your further Perl 6 adventure, would it be one-liners or industrial-scale applications. See you next year in another advent calendar, but don’t forget that perl6.online continues its work, and more posts will be published during the next 2019 year!

🎄 24/25. Reading files with $*ARGFILES in Perl 6

Welcome to Day 24 of the Perl 6 One-Liner Advent Calendar!

In the previous days, we were reading text files, so it would be logical to talk about $*ARGFILES, a built-in dynamic variable that may be handy when working with multiple input files.

How do you read two or more files passed in the command-line?

$ perl6 work.pl a.txt b.txt

If you need to process all the files together as if they would be a single data source, you could ask our today’s variable to do the job in a one-liner:

.say for $*ARGFILES.lines

Inside the program, you don’t have to think about looping over the files; $*ARGFILES will automatically do that for you.

If there are no files in the command line, the variable will be attached to STDIN:

$ cat a.txt b.txt | perl6 work.pl 

Handy indeed, isn’t it?

6.d and MAIN

I also have to warn you if you will want to use it in bigger programs. Consider the following program:

sub MAIN(*@files) {
.say for $*ARGFILES.lines;

In Perl 6.d, $*ARGFILES works differently inside the MAIN subroutine and outside of it.

This program will perfectly work with Perl 6.c, but not under Perl 6.d. In other words, in Rakudo Star up to and including version 2018.10, $*ARGFILES handles filenames in the command line, but starting with Rakudo Star 2018.12, it will be always connected to $*IN if it is used inside MAIN.

And that’s the end of today’s advent post and almost the end of the whole calendar of this year. Nevertheless, come again tomorrow!

🎄 23/25. Calculating totals with Perl 6

Welcome to Day 23 of the Perl 6 One-Liner Advent Calendar! End of the year is the time when people evaluate there year results, and Perl 6 can help with that, too.

Today, we’ll see a one-liner that calculates totals for the columns of a table.

Here’s some sample data in a file:

100.20  303.50 150.25
130.44 1505.12 36.41
200.12 305.60 78.12

And here’s the code that prints three numbers—totals for each column:

put [Z+] lines.map: *.words

The program prints the numbers that we need:

430.76 2114.22 264.78

From the update of yesterday’s post, we know that bare lines is the same as $*IN.lines, so lines.map iterates over all the lines in the input stream. Each line is then split into words—substrings separated by whitespaces.

The part of the job that parses input data is complete. We have got a number of sequences corresponding to the lines of input data. For our sample file, these are the following:

(("100.20", "303.50", "150.25").Seq, ("130.44", "1505.12", "36.41").Seq, ("200.12", "305.60", "78.12").Seq).Seq

Now, add up every first element, every second element, etc. The combination of the reduction operator and the zip meta-operators does all the work with only four characters of code: [Z+].

At this point, we have a reduced sequence:

(430.76, 2114.22, 264.78).Seq

The last trivial step is to print the values using the put routine. If you did the homework yesterday, you would know that say uses the gist method (which adds parentheses around a sequence) to visualise the result, while put simply prints the values using the Str method.

An addition

Let us add a few more characters to the script to demonstrate how you can skip the first column that, for example, contains month names:

Jan 100.20  303.50 150.25
Feb 130.44 1505.12 36.41
Mar 200.12 305.60 78.12

All you need is to make a slice and select all columns except the first one:

put 'Total ', [Z+] lines.map: *.words[1..*]

As you see, we even don’t need to count columns ourselves. The 1..* range can make that job.

And that’s the end of today’s advent post, so come again tomorrow!

🎄 22/25. Reversing a file with Perl 6

Welcome to Day 22 of the Perl 6 One-Liner Advent Calendar! Today, we will continue working with files, and the goal for today is to create a one-liner to print the lines of a text file in reversed order (as tail -r does it).

The first one-liner does the job with the STDIN stream:

.say for $*IN.lines.reverse

Run the program as:

$ perl6 reverse.pl < text.txt

Update. Thanks to the reader comment, we can gain from the fact that $*IN can be omitted in this case, which makes the one-liner even shorter:

.say for lines.reverse

If you want to read the files directly from Perl 6, modify the program a bit to create a file handle out of the command-line argument:

.say for @*ARGS[0].IO.open.lines.reverse

Now you run it as follows:

$ perl6 reverse.pl text.txt

It is important to remember that the default behaviour of the lines method is to exclude the newline characters from the final sequence of lines (the method returns a Seq object, not an array or a list). It may be opposite to what you are used to when working with Perl 5. Using chomp is quite a common practice there.

In Perl 6, the lines method splits the lines based on the value stored in the .nl-in attribute of the IO::Handle object.

You can look at the current value of the line separators with the following tiny script:

dd $_ for @*ARGS[0].IO.open.nl-in

This is what you find there by default:

$["\n", "\r\n"]

The interesting thing is that you can control the behaviour of lines and tell Perl not to exclude the newline characters:

@*ARGS[0].IO.open(chomp => False).lines.reverse.put

The chomp attribute is set to True by default. You can also change the default separator:

  nl-in => "\r", chomp => False

Notice that without chomping, you do not need an explicit for loop over the lines: in the last two one-liners, the .put method is called directly on the sequence object. In the earlier versions, the strings did not contain the newline characters, and thus they would be printed as a single long line.

I will leave you today with some small homework: Tell the difference between put and say.

Till tomorrow!

🎄 21/25. Merging files horizontally in Perl 6

Welcome to Day 21 of the Perl 6 One-Liner Advent Calendar! Only a few days left until the end of this season of advent calendars, so let’s pack as many things as possible in the remaining days, and today we’ll merge a few files into a single file 🙂

Our today’s goal is to take two (or three, or more) files and copy their contents line by line. For example, we want to merge two log files, knowing that all their lines correspond to each other.

File a.txt:

2018/12/20 11:16:13
2018/12/20 11:17:58
2018/12/20 11:19:18
2018/12/20 11:24:30

File b.txt:

"/favicon.ico" failed (No such file)
"/favicon.ico" failed (No such file)
"/robots.txt" failed (No such file)
"/robots.txt" failed (No such file)

Our first one-liner illustrates the idea:

.say for [Z~] @*ARGS.map: *.IO.lines;

It is assumed that the program is run as follows:

$ perl6 merge.pl a.txt b.txt

For each filename (@*.ARGS.map) in the command line, an IO::Path object is created (.IO), and the lines from the files are read (.lines).

In the case of two files, we have two sequences, which are then concatenated line by line using the zip meta-operator Z applied to a concatenation infix ~.

After that step, we get another sequence, which we can print line by line (.say for).

2018/12/20 11:16:13"/favicon.ico" failed (No such file)
2018/12/20 11:17:58"/favicon.ico" failed (No such file)
2018/12/20 11:19:18"/robots.txt" failed (No such file)
2018/12/20 11:24:30"/robots.txt" failed (No such file)

The result is formally correct, but let’s add a space between the original lines. Here is an updated version of the one-liner:

.trim.say for [Z~] @*ARGS.map: *.IO.lines.map: *~ ' '

Here, a space character is appended to the end of each line (.map: *~ ' '), and as there will be one extra space at the end of the combined line, it is removed by the trim method. Its sibling, trim-trailing, could be used instead (or a regex if you care about original trailing spaces happened to be in the second file).

With the above change, the files are perfectly merged now:

2018/12/20 11:16:13 "/favicon.ico" failed (No such file)
2018/12/20 11:17:58 "/favicon.ico" failed (No such file)
2018/12/20 11:19:18 "/robots.txt" failed (No such file)
2018/12/20 11:24:30 "/robots.txt" failed (No such file)

There’s no problem to merge the same file to itself, or to provide more than two files, for example:

$ perl6 merge.pl a.txt a.txt a.txt

That was it for today, come again tomorrow!

🎄 20/25. Using command-line options in Perl 6 one-liners

Welcome to Day 20 of the Perl 6 One-Liner Advent Calendar! So far, we created about 25 different one-liners, but never talked about the command-line options that the Rakudo Perl 6 compiler offers to us.


The first option to know when working with (Rakudo) Perl 6 is -e. It takes a string with your Perl 6 one-liner and executes it immediately.

For example, print the version of the current Perl 6 specification:

$ perl6 -e'$*PERL.version.say'

Be careful not to use the Perl 5.10+ styled capital -E, which does the same as -e but also activates features such as say. In Perl 6, the option is always lowercase.


This option repeats the code for each line of input data. This is quite handy when you want to process a file. For example, here’s a one-liner that adds up the values in a row and prints the sum:

$ perl6 -ne'say [+] .split(" ")' data.txt 

If the data.txt file contains the following:

10 20 30 40
1 2 3 4
5 6 7 8

then the result of the one-liner is:


There’s no difference whether you use shell’s input redirection or not; the following line also works:

$ perl6 -ne'say [+] .split(" ")' < data.txt 

Make sure you place the e option the last in the list (so, not perl6 -en'...') or split the options: perl6 -n -e'...'.


This option is similar to -n, but prints the topic variable after each iteration.

The following one-liner reverses the lines in the file and prints them to the console:

$ perl6 -npe'.=flip' data.txt

For the same input file, the result will look like this:

04 03 02 01
4 3 2 1
8 7 6 5

Notice that you have to update the $_ variable, so you type .=flip. If you only have .flip, you will reverse the string, but the result will not be used and the original line will be printed.

An equivalent program with .flip and with no -p will look like this:

$ perl6 -ne'.flip.say' data.txt


Let’s go through a few one-liners from the Perl One-Liners book and create one-liners in Perl 6.

Double-space a file

$ perl6 -npe's/$/\n/' text.txt 

Remove all blank lines

$ perl6 -ne'.say if .chars' text.txt 

Depending on how you define ‘blank’, you may want another one-liner that skips the lines containing whitespaces:

$ perl6 -ne'.say if /\S/' text.txt 

Number all lines in a file

$ perl6 -ne'say ++$ ~ ". " ~ $_' text.txt

This code, probably, requires a comment. The $ variable is a state variable and it can be used without declaration.

Convert all text to uppercase

$ perl6 -npe'.=uc' text.txt

Strip whitespace from the beginning and end of each line

$ perl6 -npe'.=trim' text.txt

Print the first line of a file

$ perl6 -ne'.say ; exit' text.txt 

Print the first 10 lines of a file

$ perl6 -npe'exit if $++ == 10' text.txt 

This time, a postfix ++ was applied to $.

I hope that was a useful journey today. See you tomorrow!