Home > Raku > Coercing coercion

Coercing coercion

Task 1 of PWC #216 is a Set-operation.

for [('abc', 'abcd', 'bcd'), 'AB1 2CD'; ('job', 'james', 'bjorg'), '007 JB'; ('crack', 'road', 'rac'), 'C7 RA2'] -> [@words, $reg] {
    say @words.grep($reg.lc.comb.grep(/<alpha>/) ⊆ *.comb);
}

The transformation of $reg is a bit unwieldy. I could pull it out and transform it before I use it but then I would have to use is rw. That ain’t neat. What if I could write a type that does the transformation for me? The answer is mildly insane.

role Trans[::From, ::To, &c] {
    has To $.value;
    method COERCE(From:D $old) {
        my \instance = self.new(:value($old.&c));
        my \table = instance.^method_table;
        table{To.^name} = my method ::To(--> To) { $!value }
        instance.^compose;

        instance
    }
}

constant ToSet = Trans[Str, Set, { .lc.comb.grep(/<alpha>/).Set }];

for [('abc', 'abcd', 'bcd'), 'AB1 2CD'; ('job', 'james', 'bjorg'), '007 JB'; ('crack', 'road', 'rac'), 'C7 RA2'] -> [@words, ToSet() $reg] {
    say @words.grep($reg ⊆ *.comb);
}

I create a parametric role that is told how to transform a Str to a Set with a Block and use that as a coercion-type. Things get tricky inside method COERCE because I have to return the role or the coercion-protocol will throw X::Coerce::Impossible. As a result I need to add a method called Set to the parametrised role. Raku doesn’t have the syntax to specify an indirection for method-names (for definitions, calling them can be done with ."$foo"). Hence the use of the MOP. Also, .^add_method doesn’t take a :local-adverb and thus refuses to overload methods provided by Mu and Any. Overwriting the name in the method table is a gnarly hack but works fine — as hacks do.

And so I got myself a way to run code at bind-time in signatures that changes arguments to what I need. I’m not sure what this could be useful for but will keep it in my toolbox nonetheless.

EVAL sadly doesn’t work, because quotes can’t form a closure over a code-object. I believe untangling this would be a nice test for RakuAST-macros and would improve readability for this example quite a bit. In fact, I wouldn’t need a parametric role but could craft a simple class.

Advertisement
Categories: Raku
  1. No comments yet.
  1. May 15, 2023 at 17:38

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: