12

The Pearls of Raku, Issue 4: unit sub MAIN and command line, round and precision

 3 years ago
source link: https://andrewshitov.com/2020/08/02/the-pearls-of-raku-issue-4-unit-sub-and-command-line-round-and-precision/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Welcome to the next issues if The Pearls of Raku ! Today, some interesting findings that I discovered while reviewing the previous weeks of The Perl Weekly Challenge and a thing that I used for the first ever time when I added a new graph to The Coronavirus Observer.

Table of Contents

unit sub MAIN

In general, the unit sub construct makes the rest of the file the body of the function. In the case of MAIN , it gives a handy way to declare parameters of your program and to restrict its values.

Imagine a command-line calculator that you run as:

$ ./calc.raku 42 + 5

You want to make sure that the first and the third arguments are integers, and there is a sign of the operation in between.

Here is a possible solution in Raku (maybe a bit exaggerated just for the sake of demonstration).

<strong>my Int $a = +@*ARGS.shift;
subset OpStr of Str where /<[-+*/]>/;
my OpStr $op = @*ARGS.shift;
my Int $b = +@*ARGS.shift;</strong>

say (given $op {
    when '+' {$a + $b}
    when '-' {$a - $b}
    when '*' {$a * $b}
    when '/' {$a / $b}
})

The highlighted part is where you get the arguments and indirectly validate them.

If you convert the code to a function, you can use function’s signature to check the arguments for you. In the case of a simple script with the only function, use unit sub MAIN :

unit sub MAIN(<strong>Int $a, Str $op where /<[-+*/]>/, Int $b</strong>);

say (given $op {
    when '+' {$a + $b}
    when '-' {$a - $b}
    when '*' {$a * $b}
    when '/' {$a / $b}
})

Also notice the difference in error reporting between these two programs. In the first case, an exception happens:

$ raku calc1.raku 42 plus 3
Type check failed in assignment to $op; expected OpStr but got Str ("plus")
  in block <unit> at calc1.raku line 3

In the second case, you get a usage message:

$ raku calc2.raku 42 plus 3
Usage:
  calc2.raku <a> <op> <b>

round

An interesting thing you may skip in the documentation is that the round routine takes an optional scale parameter. You can use it to set the number of digits after the decimal point, for example.

Round the value of π:

say pi.round; # 3

Now, print one, two, or three digits after the decimal point:

say pi.round(0.1);   # 3.1
say pi.round(0.01);  # 3.14
say pi.round(0.001); # 3.142

But that’s not all! Do you want to get only an odd number as a result? Round the value to a multiple of 2:

say pi.round(2); # 4

Set the scale to 5 or 10 and round it to a number which is a multiple of these numbers:

say pi.round(5);  # 5
say pi.round(10); # 0

You can work with big non-round numbers too. Say, let’s round the World population to see billions only:

my $population = 7_802_279_546;
say $population.round(1_000_000_000); # 8000000000

And that’s it for now. You can find the source codes of this issue on GitHub.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK