Archive

Archive for August, 2022

@data».sparkle

August 28, 2022 1 comment

While reading solutions to the PWC, I spotted a pattern. There where plenty of .map-calls that contained only simple maths. It must not be so! Task 179-2 leans itself to use vector operations.

use v6.d;

constant @sparks = "▁" .. "█";
constant \steps = +@sparks - 1;

multi MAIN(
    #| space separated list of numbers
    *@data
) {
    my $scale := @data.&{ (.max - .min) / steps };
    put @sparks[((@data »-» @data.min) »/» $scale)».round].join;
}

multi MAIN(
    #| output an example sparkline-graph
    Bool :$test
) {
    .&MAIN for <2 4 6 8 10 12 10 8 6 4 2>, <0 1 19 20>, <0 999 4000 4999 7000 7999>;
}

First, I define a character range (no need for .ord here) and store the number of bar-graph steps. Then I calculate the scale like it is used in a map (those paper-things, that always work and don’t break when dropped). Now I can use that scale to shrink (or grow) values. I believe rounding is better here then to cut of to integers.

When we feed a list to a postcircumfix:<[ ]> we get a list of values in return. However, we break the method-call chain when we do so. Since operators are just Subs with a funny syntax, we can solve that issue easily.

constant &sparks = {
    constant @sparks = "▁" .. "█";
    constant \steps = +@sparks - 1;

    &postcircumfix:<[ ]>.assuming(@sparks) but role :: { has $.steps = steps }
}.();

my $scale := @data.&{ (.max - .min) / &sparks.steps };
((@data »-» @data.min) »/» $scale)».round.&sparks.join.put;

The constants are hidden within a block-scope and only steps is exposed as part of a Subs “namespace”. By declaring &sparks as constant, I move the currying to compile time.

Hypers are not getting much use in PWC-solutions. I believe another entry in raku-did-you-know is in order.

Categories: Raku

Suspicious introspection

August 22, 2022 Leave a comment

One of my routines is acting suspicious. I’m almost certain it wilfully misinterprets arguments just so it can throw an exception. There is a way to spy on it.

sub suspicious($a, :$b, *@rest, *%opts) {
    die('imaoutahere!');

    CATCH {
        put (my $sig = &?ROUTINE.signature.gist) ~ ' -> ' ~ $sig.trans(<*@ *%> => <@ %>).EVAL».raku.join(',');
    }
}

suspicious(1, :2b, 3,4,5);
# OUTPUT: ($a, :$b, *@rest, *%opts) -> 1,:b(2),3 4 5,
          imaoutahere!
            in sub suspicious at tmp/2021-03-08.raku line 1910
            in block <unit> at tmp/2021-03-08.raku line 1917

Please note, that the CATCH-block doesn’t do anything to the exception. It is just there to trigger the debugging code. The proper place to put that would be a macro. Alas, macro can’t inject CATCH-blocks that are actually used as exception handlers. It will have to wait for RakuAST, what would also allow me to replace the EVAL-shenanigans with proper code. Another entry in macro-ideas.txt until then.

Categories: Raku

Defeating definedness

August 18, 2022 1 comment

In his latest blogpost, p6steve went through a lot of trouble to enforce definedness. I managed to shorten it a bit.

None: Nil;
subset Option of Any where Any:D | None;

my Option $defined = 42;
my Option $nothing = None;
my Option $undefined = Mu;

.&dd for $defined, $nothing, $undefined;

# OUTPUT: Type check failed in assignment to $undefined; expected Option but got Mu (Mu)

I would really like to see the content of $nothing, and while I’m on it show why Steve’s hard labour was in vain.

try {
    my Option $defined = 42;
    my Option $nothing = None;
    my Option $undefined = Mu;

    .&dd for $defined, $nothing, $undefined;

    CATCH { default { note .message; .resume } }
}

# OUTPUT: Type check failed in assignment to $undefined; expected Option but got Mu (Mu)
#         Int $defined = 42
#         Label $nothing = Label.new(name => "None", file => "tmp/2021-03-08.raku", line => 1880)
#         Any $undefined = Any

Raku is a dynamic, late bound language. There are language constructs, like resumable exceptions and NativeCall, that can defeat any type-check. Trying to use Raku like Rust, Haskell or any other strictly typed language will eventually fail. No amount of :Ds will substitute testing, testing and even more testing.

I hope not to have tested p6steve’s patience and try to calm the waves with a new repo.

Categories: Raku

Symbolism

August 14, 2022 1 comment

On IRC deoac wished to know how to print the name of a variable. This question is ambiguous. To get the name of the container is easy.

my $foo;
say $foo.VAR.name;
# OUTPUT: $foo

If binding or constants involved, things get odd or fail.

my $bar := $foo;
constant $never-changes = 'war';
# OUTPUT: $foo
          No such method 'name' for invocant of type 'Str'.  Did you mean any of
          these: 'Date', 'Num', 'are', 'none', 'note', 'take'?

The second meaning of “variable” might be “symbol” for deoac’s use case. Getting hold of a symbol name requires early compile time measures.

use experimental :macros;
macro symbol-name($symbol) {
    quasi { $symbol.Str }
}

say symbol-name($foo);
say symbol-name($bar);
say symbol-name($never-changes);
# OUTPUT: ($foo)
          ($bar)
          ($never-changes)

The value of $symbol is an AST object and stringifies (in this case) to a list of Str. I didn’t dig deeper, because with RakuAST things will change.

However, this once again shows that we might do better by explaining what my actually does instead of assuming that one can guess what we mean when using the term “variable”.

Categories: Raku