16
\$\begingroup\$

What general tips do you have for golfing in Perl 6? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Perl 6 (e.g. "remove comments" is not an answer). Please post one tip per answer.

Please note that Perl 6 is not Perl 5, so this question is not a duplicate. Most of tips for Perl 5 golfing just don't apply to Perl 6.

\$\endgroup\$
9
\$\begingroup\$

Avoid sub literals. In many cases, you can simply use {} for code blocks. For example, don't write the following code.

sub ($a){$a*2}

Instead, use blocks syntax. This also lets you to use $_, @_, and %_ placeholder variables, if you only need a single variable. If you need more, you can use $^a, $^b variables, and so on.

{$_*2}

Also, in certain rare cases, it's possible to use whatever code (especially when you have simple expressions). The * replaces the placeholder argument.

* *2
\$\endgroup\$
8
\$\begingroup\$

Perl 6 has a really bizarre feature where it allows all Unicode characters in categories Nd, Nl, and No to be used as rational number literals. Some of these are shorter than writing their numeric values out in ASCII:

  • ¼ (2 bytes) is shorter than .25 or 1/4 (3 bytes).
  • ¾ (2 bytes) is shorter than .75 or 3/4 (3 bytes).
  • (3 bytes) is shorter than 1/16 (4 bytes).
  • 𐦼 (4 bytes) is shorter than 11/12 (5 bytes).
  • 𒐲 (4 bytes) is shorter than 216e3 (5 bytes).
  • 𒐳 (4 bytes) is shorter than 432e3 (5 bytes).
\$\endgroup\$
  • \$\begingroup\$ As a follow-up for this, you can also use Unicode exponents, even with multiple digits and/or a minus: say (3² + 4², 2²⁰, 5⁻²) ==> (25 1048576 0.04). The complete list of Unicode you can abuse like this is here: docs.perl6.org/language/unicode_texas . \$\endgroup\$ – Ramillies Aug 31 '17 at 14:16
8
\$\begingroup\$

Learn the functions to read the input. Perl 6 has many interesting functions that can easily read the input from ARGV, or STDIN (if nothing was specified on ARGV), which can shorten your code if used correctly. If you call them as filehandle methods, you can force them to work on particular filehandle (useful if you for example read from STDIN, but you have to read arguments on ARGV).

get

This function gets a single line, and automatically chomps it, so you don't have to. This is useful if you need to read just a one line.

lines

This function gets all lines from the file or STDIN. It's a lazy list, so if you use it with for, it will only read what you need. For example.

say "<$_>"for lines

slurp

This will read the entire file or STDIN, and will return the result as a single string.

\$\endgroup\$
  • \$\begingroup\$ That bug was fixed -- don't know when, but say "<$_>" for lines works now \$\endgroup\$ – cat Feb 24 '16 at 22:05
5
\$\begingroup\$

Warning: Wall of text approaching. It's a lot of small tricks I gathered over time.

Write your solutions as anonymous blocks

This was mentioned already but I'd like to reiterate it. In TIO, you can write my $f = into the header, the block into the code proper, and start the footer with a ;. This seems to be by far the shortest way to get the job done (since you don't need to care about reading any input, it's given to you in the arguments).

Another nice way is using the -n or the -p switch, but I didn't find a way to make it work in TIO.

Use the colon syntax for passing arguments

That is, instead of thing.method(foo,bar), you can do thing.method:foo,bar and save 1 character. Unfortunately, you can't call another method on the result for obvious reasons, so it makes sense to use only for the last method in a block.

Use $_ as much as you can

Sometimes it's better to take a single list argument than several separate arguments because of this. When accessing $_, you may call methods on it just by starting with a dot: e. g. .sort is equal to $_.sort.

However, bear in mind that each block gets its own $_, so the parameters of the outer block won't propagate into the inner ones. If you need to access the parameters of the main function from an inner block, ...

Use the ^ variables if you can't use $_

Insert a ^ between the sigil and the variable name, like this: $^a. These work only inside a block. The compiler first counts how many of these you have in the block, sorts them lexicographically, and then assigns the first argument to the first one, the second to the second one and so on. The ^ needs to be used only in the first occurrence of the variable. So {$^a - $^b} takes 2 scalars and subtracts them. The only thing that matters is the alphabetical order, so {-$^b + $^a} does the same thing.

If you ever feel like using the pointy block syntax (like ->$a,$b {$a.map:{$_+$b}}), you're far better off writing bogus statement at the start of the block using the ^ for each argument you're not going to use in the main block (like {$^b;$^a.map:{$_+$b}}) (Note that better way to golf this is {$^a.map(*+$^b)}. I just wanted to show off the concept.)

Read through the operator docs carefully

The operators are very powerful and often they're the shortest way to get things done. Especially the meta-operators (operators that take operators as an argument) [], [\], X, <</>> and Z are worth of your attention. Don't forget that a meta-op can take another meta-op as an argument (like a XZ%% I managed to use here). You can use >> for a method call too, which can be a lot cheaper than a map (@list>>.method instead of @list.map(*.method), but beware, they're not same!). And, finally, before you use a binary << >>, bear in mind that Z will often do the same thing in much fewer characters.

If you heap a lot of meta-ops onto each other, you can specify precedence using square brackets []. That will save you when you pile up so many operators that it confuses the compiler. (That doesn't happen very often.)

Finally, if you need to coerce things to Bool, Int or Str, don't use the methods .Bool, .Int and .Str, but rather the operators ?, + and ~. Or even better, just put them into an arithmetic expression to force them into Int and so on. The shortest way to get the length of a list is +@list. If you want to calculate 2 to the power of the length of a list, just say 2**@list and it will do The Right Thing.

Use the free state variables $, @ and %

In each block, every occurence of $ (or @ or %) refers to a shiny new scalar (or array, or hash) state variable (a variable whose value persists across calls to the block). If you need a state variable that needs to be referenced only once in the source code, these three are your big friends. (Most often the $.) For instance, in the Reverse Math Cycles challenge, it could be used to choose the operators cyclically from an array, which was indexed by $++%6.

Use the sub forms of map, grep et al.

That means: do rather map {my block},list than list.map({my block}). Even if you manage to use list.map:{my block}, these two approaches come out at the same number of bytes. And often, you would need to parenthesize the list when calling a method, but not when calling a sub. So the sub approach comes out always better or at least the same as the method one.

The only exception here is when the object which is to be mapped, grepped and so on, is in $_. Then .map:{} obviously beats map {},$_.

Use junctions (& and |) instead of && and ||.

Obviously, they are 1 byte shorter. On the other hand, they must be collapsed by being forced into a boolean context. This can be always done with a ?. Here you should be aware of a meta-op !op which forces bool context, uses op and negates the result.

If you have a list and you want to turn it into a junction, don't use [&] and [|]. Instead use .any and .all. There is also .none which cannot be so easily mimicked by the junction ops.

\$\endgroup\$
  • 1
    \$\begingroup\$ I think && and || are still useful for short-circuiting? \$\endgroup\$ – ASCII-only May 18 '18 at 13:43
  • \$\begingroup\$ @ASCII-only: Yes, certainly they are. \$\endgroup\$ – Ramillies Jun 5 '18 at 12:16
4
\$\begingroup\$

Reduce the space used for variables

There's a few parts to this.

Remove whitespace

Variables declared using my can usually be declared without the space between my and the variable name. my @a is equivalent to my@a.

Use sigil-less variables

You can declare variables using a backslash to remove the sigil before the variable name, like so:

my \a=1;

(unfortunately you can't remove the space :( )

This is useful as you can then refer to them as just the bare variable name later.

 a=5;
 a.say

Basically this saves bytes if you use the variable more than once elsewhere in your code. The downside is that the variable needs to be initialised.

Use $! and $/

These pre-declared variables are usually used for exceptions and regex matches respectively, but don't need to be defined using my.

$!=1;
$/=5;

Especially useful is using $/ as an array and using the shortcuts $ followed by a number to access that element of the $/ array;

$/=100..200;
say $5;  #105
say $99; #199
\$\endgroup\$
1
\$\begingroup\$

Use ... instead of first

Typically, if you want to find the first number that matches some condition &f, you can represent it like:

first &f,1..*

However, instead you can use the ... operator:

+(1...&f)

If you have to start from 0, you can have -1 afterwards instead of +.

If you want the index of the first element in a list @a that has condition &f, normally you do:

first &f,@a,:k

Instead:

(@a...&f)-1

(or vice-versa if you want 0 indexed). In the same way, you can get all the elements up to the first one that passes the condition.

Downsides to this is that the list has to pass the condition at some point, otherwise the ... operator will try to extrapolate off the end of the list, and most likely throw an error. You also can't use Whatever code in the left hand side, since it would be interpreted as part of the sequence.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.