Archive

Author Archive

Antipairing

May 1, 2022 1 comment

As suspicious questions on IRC and Discord revealed, there are quite a few solutions to the PWC that are not made public. One question in particular indicates that there is a build-in missing in Raku.

Nemokosch: let’s say I have a 5×5 table for some reason

PWC162-2 is asking to implement an encryption algorithm that uses a simple substitution table. Having a data-struction that allowes to turn a character into a 2-dimensional @index and then use it to @replacement[||@index] would be very helpful indeed. We can use .antipairs to turn a simple list into something we can assign to a Hash and be done with it. With 2-dimension, we have to create our own.

proto sub deepantipairs(@positional, $dimensions --> Positional) {*}
multi sub deepantipairs(@a, 2) {
    @a.pairs.map({ my $outer-key = .key; .value.antipairs.map({ .key => ($outer-key, .value) }) }).flat
}
my $phrase = 'Spring has sprung!';
my @table = flat($phrase.lc.comb.grep(/\w/), 'a'..'z').unique[^25].batch(5);
my %antitable = @table.&deepantipairs(2);

# OUTPUT:

# Array @table = [("S", "p", "r", "i", "n"), ("g", "h", "a", "s", "u"), ("!", "b", "c", "d", "e"), ("f", "j", "k", "l", "m"), ("o", "q", "t", "v", "w")]
# Hash %antitable = {"!" => $(2, 0), :S($(0, 0)), :a($(1, 2)), :b($(2, 1)), :c($(2, 2)), :d($(2, 3)), :e($(2, 4)), :f($(3, 0)), :g($(1, 0)), :h($(1, 1)), :i($(0, 3)), :j($(3, 1)), :k($(3, 2)), :l($(3, 3)), :m($(3, 4)), :n($(0, 4)), :o($(4, 0)), :p($(0, 1)), :q($(4, 1)), :r($(0, 2)), :s($(1, 3)), :t($(4, 2)), :u($(1, 4)), :v($(4, 3)), :w($(4, 4))}

Let’s rotate the table (the basic idea behind the Enigma) to create a much more interesting cypher-text.

sub encrypt($phrase, $text --> Str) {
    my @table = flat($phrase.lc.comb.grep(/\w/), 'a'..'z').unique[^25].batch(5);
    my %antitable = @table.&deepantipairs(2);

    my $retval;

    for $text.lc.comb.grep(/\w/) -> $char {
        my @deepindex := %antitable{$char};
        $retval ~= @table[||@deepindex];
        @table = @table».List.flat[1..*,0].flat.batch(5);
    }

    $retval
}

say encrypt($phrase, 'As suspicious questions on IRC and Discord revealed, there are quite a few solutions to the PWC that are not made public. One question in particular indicates that there is a build-in in Raku missing.');

# OUTPUT:
# aprdnhbmdrodhvpkdtdxtjpppcuhjkuhmpdvfybpwannjpuychrfvdasojvvadgnwcqcwqkjmndpxexcepjcvjnagvpiopidyalietcknsbseejeqkbopsbpwypbrcuwknsejinlxjsmkxppwdasrrniboewbauejl

Please note the tripple “p” in the cypher. By rotating the replacement table, we mess up statistical properties of the natural language we encrypt. This makes limiting the key-space much harder.

As you likely spotted, I defined a proto with the argument $dimensions (our item may be an Iterable so we can’t infer this argument). Raku has many very handy methods defined in List that work very well with a single dimension. There may be more work to do when we start to support fixed size shaped arrays well.

Categories: Raku

A Subset of Red

April 11, 2022 1 comment

SmokeMachine reported on IRC to have found an unusual use of subset.

class Base {}
class SubClass is Base {}

multi sub trait_mod:<of>(\type, Base $base, |c) { dd type; dd c }

subset Better of SubClass where { put "where: $_"; True };

my Better $a = 42;
# OUTPUT: Better
#         \()
#         where: 42

subset creates a new type with a metaclass of Perl6::Metamodel::SubsetHOW and registers a symbol for it. The of trait is a macro-ish sub that is called at compile time, right after the new type was created. We can get hold of both arguments of that trait and do whatever we want with those type-objects. (There are no further argument, hence the \()).

The where-clause is part of the subset and is called every time we assign a value to a container which is type-checked by the type created with subset. And that is cool. We basically get a callback into container assignment but only for types that are subclasses of a user-defined type. We can even create a fancy runtime error, based on the to be assigned value.

subset Universe of Base where { die 'wrong answer' unless $_ == 42; True }
my Universe $b = 43;
# OUTPUT: wrong answer
            in block  at 2021-03-08.raku line 1513

Red is doing all sorts of fancy meta-programming and I can highly recommend to read its source. With this discovery we got another nice tool in box.

Categories: Raku

Trust issues

March 27, 2022 2 comments

On IRC japhb told us that he needs a class to trust another class that can’t see the to be trusted class.

class B {…}

class A {
    trusts B;
}

class B {

}

This is nice and simple and allows B to call private methods on A. Sadly, that only works if A and B reside in the same file because a forward declaration will cause a compile time error, unless we define the declared type in the same compilation unit.

Method resolution is a runtime creature in Raku. By carefully looking at the code, we can learn where Rakudo stores what we need to cheat with.

class A {
    has $!a = 'private';
    method !a { $!a }
}

multi sub trait_mod:<is>(Mu:U \obj, :$spying!) {
    A.^add_trustee(obj);
}

class B is spying(A) {
    has A $.a = A.new;
    method m { say $!a!A::a }
}

B.new.m;

Luckily, the trait is operates quite early at compile time, so we don’t mess up method dispatch. I’m not feeling to bad poking with a trait where I should not peek. We can always move quickly into NQP-land and break things.

    method cheating {
        use nqp;
        say nqp::getattr($.a, A, 'a');
    }

As shown above, privacy is a matter of politeness. What leaves the question, if forcing a forward declaration to be resolved locally, to be a good design decision. I shall ponder to file a problem solving issue.

Categories: Raku

That meant war

March 7, 2022 1 comment

I try to avoid to allow politics or current events to seep into my blog. The topic is the 100 year language and as such wont be history. Sadly, the head-oligarch has publicly given obvious bullshit-reasons to invade a neighbouring country. I would like to use the powers of to shed some light into the current darkness.

The official numbers (read: favouringly rounded up) for the population of Russia is 145805947 people. If only they could get themselves a decent government, that could have been quite a few hugs. But hugging they ain’t do enough, resulting in a birthrate of 1.82 children per woman. Let’s write that down.

my $woman = 145_805_947 / 2;
my $girls-per-woman := 0.91;

role Degression { }
my \degression = (2022, $woman), -> [$y, $w] { ($y + 35, $w * $girls-per-woman) but Degression } … ∞;
multi sub pretty(Degression [$year, $woman]) {
    "year: $year, Russians in RU: {$woman * 2}"
}

say degression[1000/35].&pretty;
# year: 3002, Russians in RU: 10397626.7
say "Soldiers available in {(1000/35).Int} generations: {Int(degression[1000/35][1]/$woman * 140000)}";
# Soldiers available in 28 generations: 9983

Here, I use an empty role to mark each value in the lazy list. Since I start with a 2-element list, I have to use destructuring and return a list in the generator function. The role allows for multi dispatch and other type checks, as shown in sub pretty.

Russia tries to build up independent industry for more then 10 years. That doesn’t work with a negative population growth. So they utterly depend on immigration from former soviet countries. They also depend on those counties to carry the financial burden to teaching the Russian language. Ukraine wants to join the EU in hopes to repeat the success of the Czechs (Hi Jonathan!) and Polsky (lol, Brexit!) to return to their spiritual home and grow the economy of their ancestors.

If you want to avoid future wars, don’t go to Russia. No people, no soldiers, no war. Also, being paid in ₽ may not be the most solid plan.

Categories: Raku

Self-referring labels

March 3, 2022 Leave a comment

Lizmat kindly allowed Label to expose its file and line-number. That is handy if we want to convey messages about the code itself, without having to worry about edits invalidating our line-numbers. The first use case that came to mind are lightweight singletons that are easy to find.

barcode: Nil;
qrcode: Nil;

say [barcode ~~ qrcode, barcode === qrcode, barcode =:= qrcode]; # [False False False]
put barcode; # barcode ../label-introspection.raku:16

This might be handy when sending messages through a Channel.

my $ch = Channel.new;
start {
    HERE: Nil;
    THERE: Nil;
    $ch.send(.item) for ((1, 2, HERE, THERE) xx ∞).flat;
}

.put for @$ch;
# OUTPUT: 1
#         2
#         HERE ../label-introspection.raku:24
#         THERE ../label-introspection.raku:25
#         …

If those signals end up in a Str unintended, we have a good chance to find the source of the error, even when we have to look at the sender-end of a Channel.

We can also create error messages that point to a different line then a stacktrace might.

sub may-return-nil { }

ENIL: my $var is default(Failure.new(ENIL)) = may-return-nil;
say $var;

EWHOOPSY: fail(EWHOOPSY);

CATCH {
    when X::AdHoc && .payload ~~ Label {
        put "WELP! I encountered {.name} in {.file}:{.line}" with .payload;
    }
}

POD doesn’t allow us to do compile time interpolation (yet). Since it is made up of Arrays, we can cheat.

DOCLABEL: sub described {

}

=begin pod
Sub described is defined in L<PLACEHOLDER>.
=end pod

CHECK $=pod[0].contents[0].contents[1] = DOCLABEL.&{.file ~ ':' ~ .line};

say $=pod;

# OUTPUT: [Pod::Block::Named{:name("pod")}
#             Pod::Block::Para
#             Sub described is defined in
#             ../label-introspection.raku:31
#             .
#         ]

There are quite a few things hidden in CORE and I don’t like to use nqp::attr to get hold of them. A public interface is better then an accidental one. The former make way better idioms.

Categories: Raku

Pushing …

March 1, 2022 1 comment

Thanks to , PWC 154 part 1 is so boring, I’m not going into details. Part two however is a bit of a head scratcher. We are asked to implement a sequence with the properties:

P(0) = P(1) = P(2) = 1
P(n) = P(n-2) + P(n-3)

Using the sequence operator requires a trick thought.

my \padovan = 1, 1, 1, * + * + 0 * * … ∞;
my \padovan-prime = padovan.grep(*.is-prime).unique;

I have to convince it to operate on the 1th and 2nd element of the initial list and then advance by one. For once, math is on my side because with 0 * * I can force a 3rd automatic variable into existence, without having it take part in building the sum. The rest is just filtering out anything that isn’t prime.

There is another way to skip arguments if we are willing to use a pointy-block.

my \padovan = 1, 1, 1, -> $a, $b, $ { $a + $b } … ∞;

This is not as clever but looks intentional. It’s probably better that way.

Categories: Raku

Looplessly simple

February 22, 2022 1 comment

PWC#153 is asking us to do two things that are almost comically simple, given we omit loops.

Task one would like us to output the first 10 left factorials.

sub MAIN() {
    my \leftfact = [\+] 0, 1, * * ++$ … ∞;
    say leftfact[1..10];
}

I’m doing so by writing down the definition of left factorials as a sequence and then indexing into the resulting lazy list.

In the 2nd task we need to check if the sum of the factorials of a digit equal that number.

sub MAIN(Int() $n) {
    my \fact = 1, * * ++$ … ∞;
    say fact[$n.comb].sum == $n ?? 1 !! 0
}

Again, I write down the definition of a factorial to get a lazy list in return. Then I can index into that list with a list of chars. Thankfully, Raku is considered enough to turn that list of chars into Ints for me. The sum is then checked against the whole number.

If you wonder what numbers are factorions, we can calculate them all.

my \fact = 1, * * ++$ … ∞;
fact[0..10];
.say for (^∞).hyper(:batch(1000)).grep({ fact[.comb].sum == .Int });

Hypering and sequences don’t really mix. State variables even less so. Luckily we only ever need the factorials of 0 to 10. I prime the lazy list with those values and happily hyper away.

I had a peak into the solutions on Rosattacode for left factorials. While scrolling past so many loops I had to think of Mr T.

Categories: Raku

Fuzzy commands

February 9, 2022 1 comment

Reading can make one learned. Today I had a peak into lizmat´s new module shorten-sub-commands and learned about Parameter.constraint_list. We need this method to introspect a routines literal parameters.

use MONKEY-TYPING;
augment class Parameter {
    method literal {
        !self.name && !self.named && self.type ~~ Str|Numeric && self.constraint_list == 1
            ?? self.constraint_list.head
            !! Nil
    }
}

multi sub foo('literal', 42) { }
multi sub foo($not-a-literal, 42) { }
.say for &foo.candidates».signature».params».literal;

# OUTOUT: (literal 42)
#         (Nil 42)

We can generalise lizmat´s idea of transforming command line arguments.

multi sub MAIN('foo', |c) { say 'foo', @*ARGS[0] }
multi sub MAIN('Barbara', |c) { say ['bar', @*ARGS[0]] }

sub transform-first-arg(Mu:D $test is raw, &mapper) {
    &MAIN.add_dispatchee: sub (Str:D $subcommand, |c) is hidden-from-USAGE {
        my &this-candidate := &?ROUTINE;
        my @real-subcommands = &MAIN.candidates.grep(* !=:= &this-candidate)».signature».params».[0]».literal;
        if $subcommand ~~ $test {
            MAIN(mapper($subcommand), |c)
        }
    }
}

transform-first-arg({ .lc.contains(<fo ba>.any) }, { .trans: ['fo', /:i ba.*/] => ['foo', 'Barbara'] });

This program is now very generous when it comes to it’s first argument. Even !./% bAR will result in the right MAIN-candidate to be called.

I used augment because this doesn’t feel like an ENODOC. One needs to know quite a lot of the internal workings of Parameter to make use of method constraint_list. We may have to support more then just string and numeral literals in the future. So maybe there is a PR in order.

Categories: Raku

Functional hypering

January 25, 2022 1 comment

In my last post I used a one-shot-operator to improve neatness. Sadly, by defining custom operators we also improve Rakudo’s slowness. After staring at the code form quite some time, I realised that hyper- and meta-operators are code generators. They produce a new operator in-place, which is then used with two operands. In functional programming we do the same thing by returning a sub from a sub.

multi sub hyperize(&code, '«') {
    sub (@little, @large) {
       ((@little xx *).flat Z @large).flat.map(&code)
    }
}

my &hyper-assume = hyperize({&^a.assuming($^b)}, '«');

sub sc($_) {
    .words».&{ hyper-assume((&lc, &uc), .comb)».().join }
}

Hyper-operators have a “direction” indicated by using » or «. Whereby the pointy bit points at the operand that doesn’t stop iteration. In hyperize I’m doing the same with a string literal.

However, this is terribadly slow. The culprit is .assuming, which has been reported to the authorities and will likely be fixed with RakuAST. In my case I don’t really need the fancy things .assuming does.

sub simple-assume(&routine, |tail) {
    sub (|c) {
        my \real-args = \(|tail, |c);
        routine(|real-args)
    }
}

multi sub hyperize(&code, '«') {
    sub (@little, @large) {
       ((@little xx *).flat Z @large).flat.map(&code)
    }
}

my &hyper-assume = hyperize({simple-assume(&^a, $^b)}, '«');

sub sc($_) {
    .words».&{ hyper-assume((&lc, &uc), .comb)».().join }
}

A speed up of factor 608 seems to be quite acceptable. No kidding, as soon as .assuming is involved Rakudo refuses to inline and as a consequence of that to JIT.

I will try to provide a sub assuming (right now we only have the method-form), provided I find a reasonable way to implement the advanced stuff, like skipping arguments with a Whatever.

Categories: Raku

Iterative golfing

January 24, 2022 2 comments

Lured by the Weekly, I went on twitter and lost an hour because lizmat could not resist.

sub sc($str) {
  $str.words.map({
    .comb(2).map({
      .chars == 1 ?? .lc !! .lc.flip.tc.flip
    } ).join
  }).join(" ")
}
say sc "sarcasmcase FOR YOU";
# sArCaSmCaSe fOr yOu

That’s nice and short but in my eyes, showing off on twitter should involve more Raku features. My first shot as follows.

sub sc($_) {
    .words».&{ 
        my @c = &uc, &lc;
        .comb».map({ @c = @c[1..*,0].flat; @c[0]($_);  }).join
    }.flat;
}

I’m trying to use a functional approach by building a list of functions and then rotating that list while I apply the first element in that list. Thus, &lc and &uc are called alternating. That works but looks a bit line noisy.

sub sc($_) {
    my \c = (|(&lc, &uc) xx *).cache;
    .words».&{ (.comb Z c.clone).map( -> ($c, &c) { c($c) }).join }.flat;
}

By building an infinite list of functions, I don’t need to mutate that list. Just using Z will create the right amount of iterators in the background to alternate &lc and &uc. I’m still not happy with the map-part.

sub sc($_) {
    .words».&{ (.comb »,» (&lc, &uc)).flat.map({ &^b($^a) }).join }.flat
}

That’s much shorter and I don’t need to build the infinite list of functions by hand any more. Of cause, that list still exists. It is just hidden within the hyper operator. I’m still not happy with the .map. I’m building a pair of a value and a function-object. If I could .assume, I would not need the .map at all.

multi sub infix:<⊙>(&c, +@a) {
    &c.assuming(|@a)
}
sub sc($_) {
    .words».&{ ((&lc, &uc) «⊙« .comb)».().join }
}

By turning .assuming into an infix, I can use it straight in the hyper-operator. The resulting list of .assumed function can then be called via »..

Infix operators allow us to play functional tricks with very few keystrokes. We already got ∘ to combine functions. It may make sense to include ⊙ into CORE too. I’m not sure about its Texas-variant thought. Any suggestions?

Categories: Raku