Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering elements matching two regexes in Perl 6

Tags:

raku

Something is going on here that I don't quite understand.

> my @arr = <ac bc abc>
> @arr.grep: (( * ~~ /a/ ) && ( * ~~ /b/ ))
(bc abc)

But

> @arr.grep(* ~~ /a/).grep(* ~~ /b/)
(abc)

What's the reason?

like image 937
Eugene Barsky Avatar asked Sep 30 '18 09:09

Eugene Barsky


1 Answers

You've come up with perfectly cromulent solutions.

Another would be:

my @arr = <ac bc abc>
@arr.grep: { $_ ~~ /a/ && $_ ~~ /b/ }
(abc)

The rest of this answer just explains the problem. The problem in this question is a more complicated version of the problem covered at WhateverStar && WhateverStar.


The logical ops don't execute their arguments if they're code.

So { $_ ~~ /a/ } && { $_ ~~ /b/ } returns { $_ ~~ /b/ }.

Or * ~~ /a/ && * ~~ /b/ returns * ~~ /b/.

At the same time, grep does execute its matcher if it's code or if it's a regex, so these are all the same:

foo.grep: { $_ ~~ /.../ }
foo.grep:    * ~~ /.../;
foo.grep:         /.../;

The magic of Junctions

Your Junction solution seems natural. I'd love it if someone could explain what I'm missing in the following. While I expected it to work, it's bending my head to figure out how it actually works but I think it's something like (but not quite):

  • foo & bar becomes a Junction of foo and bar.

  • An attempt is made to invoke grep with a Junction as an argument.

  • Because Junction is outside the normal Any value hierarchy, most routines don't have a matching signature. grep doesn't.

  • When you invoke a routine and there is no corresponding signature then the initial dispatch fails and we hit a dispatch fallback handler. This may be the method one.

  • If the dispatch fallback handler sees there are Junction arguments then it extracts the individual values in the Junction and fires up logically parallel "threads" (currently never actual threads, but the compiler is allowed to make them real threads if it thinks that is a good idea) corresponding to those values. Thus it invokes grep twice per element of the invocant and outputs the results back into a new Junction of the same type as the incoming Junction.

  • In boolean context, a Junction collapses to a single result.

  • (If a Junction is in an overall boolean context then it can (parallel) short-circuits based on results. If it's an any and any result comes in True then it can cancel the rest -- or not do them in the first place if it's actually doing things sequentially, as is currently always the case. If it's an all and any result comes in False it can cancel the rest. Etc.)

like image 107
raiph Avatar answered Nov 15 '22 22:11

raiph