loading...

The Weekly Challenge in Raku : Week 72 (Part 2)

scimon profile image Simon Proctor ・3 min read

So Part 1 was interesting and I've got a final coda to that. Here's probably the smallest and fastest way to solve the challenge.

unit sub MAIN( UInt $N where * <= 10 );
say '00000111112'.comb[$N];

...

Yup. So lets break this down. First up the unit declarator says everything in the current file is part of the MAIN sub. It's not really required but I liked it.

'00000111112'.comb takes the string and splits it into a list. It's a bit shorter than writing the list with commas. Then we simply look up the index for $N in the list.

This works because of the restriction on $N that it can't be greater than 10 so we can pre-calculate the results. This may seem like "cheating" but it's an important trick for a developer to have. Sometimes it's faster to pre-calculate and cache data than it to make it on the fly.

Anyway onto the second task.

Task 2

So for this one I'm just going to share my whole answer and then go over what it's doing :

subset FilePath of Str where *.IO:f;

#| Read and output lines A -> B in the given text file
sub MAIN (
    UInt $A where * > 0, #= Start line
    UInt $B where * >= $A, #= End line
    FilePath :f(:$file) = "test-file.txt", #= Text file to read
) {
    .say for $file.IO.lines[$A-1..$B-1];
}

Yes. The answer is 1 line of code. Everything else is validating input values, this is my favourite kind of function. Especially when the input validation is not done inside the function.

For the validation we firstly define a subset of the Str type. Subsets are effectively named where clauses which make the code easier to read and also make the computed Usage message nicer to read as well.

The where clause casts our String to an IO object (treating it as a path) and then checks there's a file at that location.

Note the UInt is a subset of Int and that as with $A and $B you can combine a subset and an additonal where clause. Also as in $B you can reference other parameters in your where clauses.

In all I love this signature for displaying the power of signatures in Raku it allows you to take a lot of the boiler plate for validation and shift it up, often allowing for compile time checking.

And now the meat of the function. $file.IO makes an IO::Path object that points to the file we want to read. Then we call the lines method to get a sequence that returns lines in the file. (This is evaluated lazily which is nice).

Next we slice the sequence from $A-1 (as the challenge specifies indexing from 1 and Raku indexes from 0) to $B-1 and finally print each line with the .say method. When you call for and don't define the variable it uses $_ and when you call a method without an object you use $_ so bingo.

One of the things I love about Raku is it's ability to make things that you need to do often really really simple. Leaving you time to focus on the interesting problems.

Posted on by:

scimon profile

Simon Proctor

@scimon

Was an Englishman in Scotland but now back in England. Gamer, coder and voracious devourer of information. Occasionally writes stuff.

Discussion

markdown guide