## @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 `Sub`s 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 `Sub`s “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

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 `:D`s 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

## Swarming Sundays

July 30, 2022 1 comment

To not miss any Sundays, PWC 175 is asking us to find them. Raku helps us a great deal, because we can easily find the last day in a month, calculate it’s distance to the next Sunday and turn the clock back by that many days.

``````for 2022 -> \$year {
for 1..12 -> \$month {
my \$last-day-in-month = Date.new(\$year, \$month, *);
my \$Δsunday = \$last-day-in-month.day-of-week % 7;
say \$last-day-in-month.earlier(:days(\$Δsunday));
}
}``````

If you follow this blog, you will have spotted my distaste for simple loops. They get in the way of using interesting language features and thus fun. `Date.new` will only ever return a single date. With an `Array` of dates I could use vector operations to calculate all last Sundays in a month in one go. So I need a way to create a swarm of `Date`s, depending on a pattern. `Signature`s are patterns (and just fancy lists), so let’s use those.

``````sub swarm(::Type, @sig is copy, Range \$range) {
my \$var;
my \$marker-index = @sig.first([], :k);
@sig[\$marker-index] := \$var;
gather for @\$range {
\$var = \$_;
take Type.new: |@sig;
}
}

my @months = swarm(Date, (2022, @, *), 1..12);
my @Δsunday = @months».day-of-week »%» 7;
.say for @months.map({ .earlier(:days(@Δsunday.shift)) });``````

The `sub` swarm takes a type, a parameter-list meant to be used on that types’ `new` method and a range. It finds the empty list created by `@` and replaced it with a container. That container is then filled with a value taken from the range. This is as neat as it is unnecessary. Raku will do the whole shebang for us if we use a `Junction`. Getting hold of the results requires a module by lizmat.

``````use eigenstates;

my @months = Date.new(2022, (1..12).any, *).&eigenstates;
my @Δsunday = @months».day-of-week »%» 7;
.say for @months.map({ .earlier(:days(@Δsunday.shift)) });

# OUTPUT: No such method 'List' for invocant of type 'BOOTArray'.  Found 'List'
on type 'Any'
in sub eigenstates at /usr/local/src/rakudo/install/share/perl6/site/sources/EDAA4AE0C8813633A2EA392374FB72F6B4D61047 (eigenstates) line 4``````

Thank you MoarVM, for creating a nice `BOOTArray` for us that we can’t easily turn into a `List`. Some bewilderment and a PR later, the result changed. You may wish to `zef upgrade` if you `use eigenstates`.

``````2022-01-30
2022-02-27
2022-03-27
2022-04-24
2022-05-29
2022-06-26
2022-07-31
2022-08-28
2022-09-25
2022-10-30
2022-11-27
2022-12-25``````

Just displaying those Sundays wont justify getting rid of the loop. If we need that in an API, returning a list of `Date`s without much hassle seems valuable. Please note, that the `BOOTArray` indicates eagerness and I don’t think it has to be. `Junctions` might get lazier and faster in the future.

Categories: Raku

## Coercive bits

July 13, 2022 1 comment

Altreus was looking for a way to convert a list of bitmask names, provided as a string by the user, to a bitmask. He wished for BUILDARGS, as provided by Perl’s Moose but was given good advise how to solve the problem without making object instantiation even more complex. Nobody can stop me from doing just that.

With Moose, BUILDARGS allows to modify values before they are bound to attributes of a class. We can do the same by using the COERCE-protocol, not just for `Routine`-arguments.

``````role BitMask[@names] {
sub names-to-bits(@a) {
for @a -> \$s {
}

}
(\$mask.base(2).comb.reverse Z @names).map: -> [Int() \$is-it, \$name] { \$is-it ?? \$name !! Empty }
}

multi method COERCE(Str \$s) { self.COERCE: \$s.split(' ').list }
multi method COERCE(List \$l) { self.new: :mask(\$l.&names-to-bits) }

method bits(--> Str) { \$.mask.fmt('%b') }
}

class C {
has BitMask[<ENODOC ENOSPEC LTA SEGV>]() \$.attr is required;
}

my \$c = C.new: :attr<ENODOC ENOSPEC SEGV>;
say \$c;
say \$c.attr.bits;
# OUTOUT: C.new(attr => BitMask[<ENODOC ENOSPEC LTA SEGV>](<ENOSPEC LTA SEGV>))
#         1011 ``````

Here I build a role that carries the names of bits in a bit-field and will create the bit-field when give a `Str` or `List` containing those names. Since I use a parametrised role, my bitfield is type-safe and the type is tied to the actual names of the bits. As a consequence a user of the module that exports `C` can extend the accepted types by using that specific role-candidate.

``````enum IssueTypes ( ENODOC => 0b0001, ENOSPEC => 0b0010, LTA => 0b0100, SEGV => 0b1001 );

class IssueTypesBits does BitMask[<ENODOC ENOSPEC LTA SEGV>] {
method new(*@a where .all ~~ IssueTypes) {
}
}

sub bitmask(*@a where .all ~~ IssueTypes) {
IssueTypesBits.new: |@a
}

my \$c3 = C.new: attr => BEGIN bitmask(ENODOC, LTA, SEGV);
say \$c3;
say \$c3.attr.bits;
# OUTPUT: C.new(attr => BitMask[<ENODOC ENOSPEC LTA SEGV>](<ENODOC LTA SEGV>))
1101``````

Here I define an `enum` and provide the same names in the same order as in `does BitMask`. With the shim `bitmask` I create the type-safety bridge between `IssueTypes` and `BitMask[<ENODOC ENOSPEC LTA SEGV>]`.

It is very pleasing how well the new `COERCE`-protocol ties into the rest of the language, because we can use a coercing-type at any place in the source code which takes a normal type as well. What is not pleasing are the LTA-messages `X::Coerce::Impossible` is producing.

``````my \$c4 = C.new: attr => 42;
# OUTPUT: Impossible coercion from 'Int' into 'BitMask[List]': method new returned a type object NQPMu
in block <unit> at parameterised-attribute.raku line 60``````

This is surpring because we can get hold of the candidates for `COERCE` at runtime.

``````CATCH {
when X::Coerce::Impossible && .target-type.HOW === Metamodel::CurriedRoleHOW {
put "Sadly, COERCE has failed for {.from-type.^name}. Available candidates are: ", .target-type.new.^lookup('COERCE').candidates».signature».params[*;1]».type.map(*.^name)
}
}

# OUTPUT: Sadly, COERCE has failed for Int. Available candidates are: Str List``````

What we can’t see are the candidates of `IssueTypesBits`, because that is hidden behind the constructor `new`. I tried to use the MOP to add another multi candidate but failed. When parametrising the underlying type-object gets cloned. Any change to the multi-chain wont propagate to any specialised types.

The COERCE-protocol is quite useful indeed. Maybe it’s time to document it.

Categories: Raku

## The truth is a hard problem

In a recent article, stevied promised a detailed walk through of code. I asked him if he would be interested in a critique of his writings. He foolishly agreed.

He claims that `Array`s are eager and fill all memory if given the chance. Let’s check this claim.

``````my @a = 1, 1, * + * … ∞;
say @a.WHAT;

# OUTPUT: (Array)``````

`Array.STORE` goes out of it’s way to maintain iterables (not all things that are iterable do `Iterable`) and only reify container slots that we actively ask for. It will cache lazy lists by default, assuming that when we use `.AT-POS` (usually indirectly with a positional subscript) we want to use the values again. Dealing with lazy lists is a hard problem and many get it wrong (as my next blog post will discuss in more detail).

In the next paragraph I found another inaccurate statement. `Int:D` does not check for definedness.

``````multi sub bar(Any:D \$) { say 'defined'; }
multi sub bar(Any:U \$) { say 'undefined'; }

bar(Int); # undefined

class C { method defined { False } }
my \$c = C.new; # undefined
bar(C); # undefined
bar(\$c); # defined
say defined \$c; # False
say \$c.DEFINITE; # True
say \$c // 'undefined'; # undefined``````

In Raku objects are either type objects or definite objects. The latter are the result of `nqp::create`. Raku and most user code expects objects to provide a basic set of methods that can be found in `Mu` or `Any`. The default type-check is against `Mu`. We can check if an object is definite with the macro `.DEFINITE` (you can overload a method of the same name, but Rakudo will ignore it) or, if we also want to know if we got an ordinary object, with `\$foo ~~ Mu:D`. There is a clear distinction of definedness and being definite. Raku needs to make that differentiation to support “unusual” values and types like `Nil` and `Failure`. Please note, that type-objects are not definite but can be defined. Types are a hard problem.

In the same paragraph stevied writes: “defined integer object”, even though he makes a type-check against `Int`.

``````multi sub foo(Int:D \$i) { }
multi sub foo(\$i where { \$i - \$i.truncate == 0 }) { say 'lolwut‽' }
multi sub foo(\$) { say 'not integer'; }

foo(1.0);
foo(1/1);
foo(¼);

# OUTPUT: lolwut‽
lolwut‽
not integer``````

`Int:D` will fail for any value that doesn’t got `(Int)` in its `.^mro` or is a `subset` of `Int` or any of `Int`‘s sub-classes. Raku sports an excellent coercion protocol and there is no reason not use it.

``````subset PositiveInteger of Numeric:D() where { \$^i > 0 && (\$i - \$i.truncate == 0) || fail("Expected a positive and an integer value but got \$i.")}
sub get-prime(PositiveInteger \$nth where * > 0) {
say (\$x.grep: *.is-prime)[\$nth - 1];
}
get-prime('5');
get-prime(½);
# OUTPUT: 11
Expected a positive and an integer value but got 0.5.
in block  at 2021-03-08.raku line 1809
in block <unit> at 2021-03-08.raku line 1288``````

A value check is needed in this instance because `.AT-POS` will coerce to `Int` (by truncating) what may give a reasonable answer for an unreasonable question. No matter how sharp the knife, we wont get the ½th prime number. Being positive and integer is a hard problem.

Please don’t use `say` unless you actually want to run `.gist`.

``````say Nil;
put Nil;
# OUTOUT: Nil
Use of Nil in string context
in block  at 2021-03-08.raku line 1818``````

When you `say` you may miss subtile bugs, especially when running CI-tests.

Further down we find `Sequence` but `grep` returns a `Seq` – in this example. I never had to make the distinction between `Seq` and `HyperSeq` but the latter is not a child of `Cool` so a lot of interfaces are missing. The same is true for the role `Sequence`. The build-in types are a hard problem.

If we must ask what exactly `*` is (I wouldn’t, because that’s a really hard question.), it is best to provide the correct answer.

``````my &b = * + *;
say .WHAT, .signature with &b;
my &b2 = { \$^a + \$^b };
say .WHAT, .signature with &b2;
# OUTPUT: (WhateverCode)(;; \$whatevercode_arg_11 is raw, \$whatevercode_arg_12 is raw)
(Block)(\$a, \$b)``````

A `WhateverCode`-object will have all its arguments as `is raw`, what means it will always have access to the containers used by the callee (There are many things we can do, but probably shouldn’t, with `.VAR`). It will never have control exceptions (no `return` or phasers, etc.), doesn’t have a proper scope (no `use`-statement) and a few more things. The idea is to have a subclass of `Code` that is so simple that the compiler can always inline it. Code-objects are a hard problem.

I would have written that code a little different.

``````sub get-primes(*@nth) {
(^∞).hyper.grep(-> Int:D() \$_ is raw { .is-prime })[@nth »-» 1]
}

.put for get-primes(5, 50, 500, 5000, 50000);``````

I spend a pretty penny on that Threadripper, so I better `.hyper` as often as I can. If sensible I try to use a slurpy to move the burden of dealing with plurals from the user to the implementer. We can ask `.AT-POS` for a list of values, so there is no reason not to.

There are quite a few more inaccuracies in Steve’s article. Bless him, Raku is a bitch and we are not good at explaining how the language actually works. For most programs that doesn’t matter, they will run just fine even if the programmer is sloppy. I learned most of the gritty details when tracking down bugs. Granted, I stick my arm deep into the machinery, so it’s my own bloody fault when I get pinched. Since bugs happen we need to get better at explaining how to hunt them down. Raku is a hard problem.

Categories: Raku

## Sinking Errors

June 26, 2022 1 comment

I was looking for a way to output debug messages that can also carry additional values, when not output to the screen. That is easy. The tricky part is golfing the interface. After quite a bit of struggle. I ended up with the following.

``````use Log;

dd ERROR('foo') ~~ LogLevel::ERROR;
dd ERROR('foo') ~~ LogLevel::DEBUG;
say ERROR('foo').&{ .file, .line };
VERBOSE 'Detailed, very much so indeed.';
my \$*LOGLEVEL = 2;
VERBOSE 'Detailed, very much so indeed.';

# OUTPUT:
# Bool::True
# Bool::False
# (2021-03-08.raku 1661)
# 2021-03-08.raku:1664 Detailed, very much so indeed.``````

In sink-context, the “functions” will output to `\$*ERR` and when not sunk return an object that provides a few useful methods. To get both, we need to implement the methods `sink` and `CALL-ME`.

``````# Log.rakumod

use v6.d;

my role Functor {
has \$.message;
my \$.level;
has \$.captured-loglevel;
has \$.file;
has \$.line;
method CALL-ME(*@message) {
my (\$line, \$file) = callframe(1).&{ .line, .file };
self.new: message => "\$file:\$line " ~ @message.join(\$?NL), :captured-loglevel(\$*LOGLEVEL // 0), :\$line, :\$file;
}
method sink { \$*ERR.put(self.message) if (\$!captured-loglevel // 0) ≥ \$.level }
method Str(::?CLASS:D:) { self.message }
method gist(::?CLASS:D:) { self.^shortname ~ ' ' ~ self.message }
}

my \$ERROR;                                                                                                                                                                    my \$VERBOSE;
my \$DEBUG;

class LogLevel {
constant ERROR := \$ERROR;
constant VERBOSE := \$VERBOSE;
constant DEBUG := \$DEBUG;
}

\$ERROR = class :: is LogLevel does Callable does Functor { my \$.level = 1; }
\$VERBOSE = class :: is LogLevel does Callable does Functor { my \$.level = 2; }
\$DEBUG = class :: is LogLevel does Callable does Functor { my \$.level = 3; }

sub EXPORT {
Map.new: '&ERROR' => \$ERROR,
'&VERBOSE' => \$VERBOSE,
'&DEBUG' => \$DEBUG,
'LogLevel' => LogLevel,
}``````

To behave like a function a `Callable` must be bound to an `&`-sigiled symbol (or Rakudo complains when we use it as a term). As soon as Rakudo spots a class, it will stuff it into `UNIT::EXPORT::ALL`. When importing any `&`-sigiled key of `sub EXPORT`, with the same basename as a class with that basename, the symbol from `EXPORT` will be ignored. The only way to avoid that is to have anonymous classes and do the forward-declarations by hand. The latter is needed to allow `ERROR('foo') ~~ LogLevel`.

All that is a bit convoluted but works as expected. What I didn’t expect, is that dynvars that are user-defined are not visible in `method sink`. Not much of a problem in my case, as capturing the state of `\$*LOGLEVEL` inside `CALL-ME` is the right thing to do anyway. What threw me off is the inconsistency with other functions and methods that are called by a time-machine. We type `BEGIN`, `BUILD` and friends in all-caps for that very reason. This may warrant a problem solving issue. It’s an ENODOC for sure.

I believe golfing APIs is a most desireable effort. Laziness isn’t just a virtue for programmers, often it’s a given.

Categories: Raku

## Reducing sets

May 25, 2022 1 comment

This week´s PWC asks us for hexadecimal words and distinctly different directories.

``````sub term:<pwc-166-1> {
sub less-substitutions-then (\$_, \$n) {
.subst(/<-[olist]>/, :g, '').chars < \$n
}

'/usr/share/dict/words'.IO.words.race\
.grep({.chars ≤ 8 && .&less-substitutions-then(4)})\
.map(*.trans(<o l i s t> => <0 1 1 5 7>))\
.grep(/^ <[0..9 a..f A..F]>+ \$/)\
.sort(-*.chars)\
.say;
};``````

Once again, we write the algorithm down. Get the words, drop anything longer then 8 chars or what would need more then 4 substitutions. Then do the substitutions and grep anything that looks like a hexadecimal numeral. Sort for good measure and output the first 100 elements.

The second task provides us with a little challenge. We need to mock listing directories and working with them. Since `dir` returns a sequence of `IO::Path` I can create those by hand and mixin a role that mimics some filesystem operations. I can overload `dir` to provide a drop-in replacement.

``````sub term:<pwc-166-2> {
sub basename(IO::Path \$_) { .basename ~ (.d ?? '/' !! '') }
sub pad(Str \$_, \$width, \$padding = ' ') { .Str ~ \$padding x (\$width - .chars) }

sub dir(Str \$name) {
sub mock-file(*@names) { @names.map({ IO::Path.new(\$_) but role :: { method f ( --> True ) {}; method e ( --> True ) {} } } ) }
sub mock-dir(*@names) { @names.map({ IO::Path.new(\$_) but role :: { method d ( --> True ) {}; method e ( --> True) {} } }) }

constant %dirs = dir_a => flat(mock-file(<Arial.ttf Comic_Sans.ttf Georgia.ttf Helvetica.ttf Impact.otf Verdana.ttf>), mock-dir(<Old_Fonts>)),
dir_b => mock-file(<Arial.ttf Comic_Sans.ttf Courier_New.ttf Helvetica.ttf Impact.otf Tahoma.ttf Verdana.ttf>),
dir_c => mock-file(<Arial.ttf Courier_New.ttf Helvetica.ttf Impact.otf Monaco.ttf Verdana.ttf>);

%dirs{\$name}
}

sub dir-diff(+@dirs) {
my @content = @dirs».&dir».&basename;
my @relevant = (([∪] @content) ∖ [∩] @content).keys.sort;

my @columns = @content.map(-> @col { @relevant.map({ \$_ ∈ @col ?? \$_ !! '' }) });
my \$col-width = [max] @columns[*;*]».chars;

.put for ([Z] @columns)».&pad(\$col-width)».join(' | ');
}

dir-diff(<dir_a dir_b dir_c>);
};``````

I’m asked to add a `/` to directories and do so with a custom `basename`. The rest is liberal application of set theory. Only names that don’t show up in all directories are relevant. Columns are created by matching the content of each directory against the relevant names. The width of columns is the longest string. The header is put on screen. To output the columns line by line, x and y are flipped with `[Z]`.

After careful study of the solutions written in other languages, I believe it is fair to call Raku an eco-friendly language. Our keyboards are going to last at least twice a long.

Categories: Raku, Uncategorized

## Writing it down

PWC 165 refers us to mathsisfun for the algorithm to be used. Let’s write it down.

``````    my \$input = '333,129  39,189 140,156 292,134 393,52  160,166 362,122  13,193
341,104 320,113 109,177 203,152 343,100 225,110  23,186 282,102
284,98  205,133 297,114 292,126 339,112 327,79  253,136  61,169
128,176 346,72  316,103 124,162  65,181 159,137 212,116 337,86
215,136 153,137 390,104 100,180  76,188  77,181  69,195  92,186
275,96  250,147  34,174 213,134 186,129 189,154 361,82  363,89';

my @points = \$input.words».split(',')».Int;

my \term:<x²> := @points[*;0]».&(*²);
my \xy = @points[*;0] »*« @points[*;1];
my \Σx = [+] @points[*;0];
my \Σy = [+] @points[*;1];
my \term:<Σx²> = [+] x²;
my \Σxy = [+] xy;
my \N = +@points;

my \$m = (N * Σxy - Σx * Σy) / (N * Σx² - (Σx)²);
my \$b = (Σy - \$m * Σx) / N;

say [\$m, \$b];``````

That was exceedingly simple. If the point cloud is large, this might also be exceedingly slow. There are no side effects and everything is nice and constant. Should be easy to get the CPU busy.

``````    sub delayed(&c) is rw {
my \$p = start { c };
Proxy.new: STORE => method (|) {}, FETCH => method { await \$p; \$p.result }
}

my \term:<x²> = delayed { @points[*;0]».&(*²) };
my \xy = delayed { @points[*;0] »*« @points[*;1] };
my \Σx = delayed { [+] @points[*;0] };
my \Σy = delayed { [+] @points[*;1] }
my \term:<Σx²> = delayed { [+] x² };
my \Σxy = delayed { [+] xy };
my \N = +@points;

my \$m = (N * Σxy - Σx * Σy) / (N * Σx² - (Σx)²);
my \$b = (Σy - \$m * Σx) / N;

say [\$m, \$b];``````

Since I use sigil-less symbols, I get binding for free. This in turn makes using `Proxy` easy. The `await \$p` part is called more then once per `Proxy` but not in a loop so there is no real need to optimise here. On my box the `Proxy`ed version is almost twice as fast. A nice win for such a simple change.

I somehow feel this solution might please a mathematician — as Raku should.

Categories: Raku