develooper Front page | perl.perl6.users | Postings from October 2019

Re: Match operator: error with any() junction and user-defined $_topic variable

Thread Previous | Thread Next
From:
Brad Gilbert
Date:
October 8, 2019 17:54
Subject:
Re: Match operator: error with any() junction and user-defined $_topic variable
Message ID:
CAD2L-T3pmGSrPExUo-3h8DZFGL+SvqOJ+Hoqa6kHiy6eh0LZPg@mail.gmail.com
Most operations with Junctions produce Junctions.

    > 1 + any(2, 3)
    any(3, 4)

    > any(1, 2) + 3
    any(4, 5)

    > any(<ab cd>) ~~ /./
    any(「a」, 「c」)

In the case of the following line, `$/` gets assigned a junction of the
results.

    > if any(@genus) ~~ m/Hama/ { put "Matches at least one again"; };

The `m/Hama/` is executing early in the smartmatch `~~`.
Really you should have been using `rx/Hama/` or `/Hama/` instead.

    > any(<ab cd>) ~~ m/./
    False

`m//` always executes against `$_`. While `rx//` always evaluates to the
regex itself.
(`/…/` will do one or the other depending on context.)
So there are some places where `m//` appears to wait to execute like the
following line.

    > 'abc' ~~ m/b/

It doesn't wait. It executes immediately.


The reason is that smartmatch is actually a two step process.
The above example is basically short for the following line:

    > (do given 'abc' { m/b/ }).ACCEPTS('abc')

Now I am going to simplify it.
The `m/b/` executes immediately.

    > (do given 'abc' { 「b」 }).ACCEPTS('abc')
    > (                 「b」  ).ACCEPTS('abc')

Since `.ACCEPTS` on an instance of Match always returns itself, the above
returns the Match object.

It would operate differently, but come to the same result with `rx//`.

    > (do given 'abc' { rx/b/ }).ACCEPTS('abc')
    > (                 rx/b/  ).ACCEPTS('abc')

Since `rx/b/` does indeed accept 'abc' the end result of the above line is
the Match object 「b」.


In the case of a Junction, the `~~` applies to each part of the junction
separately, and then combines the results.
So `$/` gets assigned a Junction rather than the normal Match.
(Which means `m//` and `rx//` do not come to the same result.)

If the book says that `@genus ~~ m/Hama/` and `any(@genus) ~~ m/Hama/` are
exactly the same, it is incorrect.
The first sets $/ and returns the first value that returns a True value.
While the second returns True and sets $/ to a Junction of all the results.


Then later when you do just `m//` it tries to assign to each value in the
Junction to the new result.
Since the junction contains immutable values, that doesn't work.

    > $_ = 'abc';
    > $/ = any 'def', 'ghi';
    > m/abc/
    Cannot modify an immutable Str (def)
      in block <unit> at <unknown file> line 1

Basically when `m//` tries to do `$/ = …` it threads through the Junction
rather than just assigning directly to `$/`.
It is a bug in the assignment code that m// uses.


When submitting a bug report, it is best to reduce the problem to the
simplest example that still produces the error. The last example here does
just that.
This is a compiler / runtime issue. The compiler's name is Rakudo, so the
appropriate repository would be https://github.com/rakudo/rakudo.
Since you found the issue, I think you should create the issue in the bug
tracker.
(Mainly because that is a common first stepping stone to getting involved.)



On Tue, Oct 8, 2019 at 2:53 AM William Michels via perl6-users <
perl6-users@perl.org> wrote:

> Greetings:
>
> I tried the following regular expression code, working generally from
> "Learning Perl 6" by brian d foy (Chapter 15). Everything works fine
> including the any() junction below, as long as the topic $_ variable
> isn't defined beforehand. However specifically in combination with a
> user-defined $_ topic variable, an any() junction returns the error,
> "Cannot modify an immutable Match." See Perl6 REPL code below (also
> checked with 6Pad (https://perl6.github.io/6pad/)) :
>
> mbook:~ homedir$ perl6
> To exit type 'exit' or '^D'
> > $_ = 'Hamadryas';
> Hamadryas
> > my @genus = < Hamadryas Sostrata Junonia >;
> [Hamadryas Sostrata Junonia]
> > say $_.WHAT, $/.WHAT;
> (Str)Nil
> > if @genus ~~ m/Hama/ { put "Matches at least one"; };
> Matches at least one
> > say $_.WHAT, $/.WHAT;
> (Str)(Match)
> > say m/Hama/;
> 「Hama」
> > say m/Hama/;
> 「Hama」
> > say $_.WHAT, $/.WHAT;
> (Str)(Match)
> > if any(@genus) ~~ m/Hama/ { put "Matches at least one again"; };
> Matches at least one again
> > say $_.WHAT, $/.WHAT;
> (Str)(Junction)
> > say m/Hama/;
> Cannot modify an immutable Match (「Hama」)
>   in block <unit> at <unknown file> line 1
>
> > say $*VM
> moar (2019.07.1)
> >
>
> I understood from the "Learning Perl 6" book that the two smart-match
> lines of code are equivalent--the first one simply understands that
> there is an 'implied' any() junction to check the array against the
> match operator. But REPL reports back that in one case $/ returns a
> match object type, while in the other case [with an explicit any()
> junction], $/ returns a junction object type. So this feels
> inconsistent, at the very least.
>
> Any explanation appreciated. If after triaging this issue, someone
> would like me to open a Github issue, please point me towards the
> correct repository.
>
> Thanks, Bill.
>
> W. Michels, Ph.D.
>

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About