5

The invert method for Lists should return the inverted sequence, or at least that's what the source seems to imply. However:

say (1,3,2).invert 

fails with:

(exit code 1) Type check failed in invert; expected Pair but got Int (1)␤  in block <unit>

The documentation does not help, because it's LTA in this area (and missing for List). But the source code does not admit any ambiguous interpretation. Is there anything I'm missing here?

jjmerelo
  • 22,578
  • 8
  • 40
  • 86

2 Answers2

5

Perhaps you intended to use the reverse method. Well, if you want the result to be (2,3,1).

It looks like the documentation of List.invert is indeed missing. It is intended to work only on a List that consists of Pairs. I'll write that up now.

EDIT: doc added with https://github.com/perl6/doc/commit/0ee3245776

Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
4

In Perl6, operators subroutines and methods have a singular purpose for a given name.

In the case of the infix + operator it is to add two numbers. So if it is given something that is not a number it tries to turn it into a number before adding.

In the case of the .invert method, its fundamental purpose is to invert a Pair object. That is swap the .key and the .value of a Pair.

So everywhere that .invert can be used, it does so in the way that is most like inverting a Pair object.


On a Pair object with a singular .value, it swaps the key and the value.

say ('a' => 'A').invert;
# (A => a)

If the .value is not singular it gives you a sequence where each value is now the key of its own Pair.

say ('a' => ('A', 'B')).invert;
# (A => a B => a)

Note that .invert always returns a sequence to be consistent. Even on that first example.

On a Hash it does it on all of the key / value pairs.

say %( 'a' => ('A','B'), 'b' => 'B', 1 => 'A' ).invert.sort;
# (A => 1 A => a B => a B => b)

On a List, it could do it one of two ways.

  1. It could use the index as the key, exactly like .antipairs does.

    say ( 'a' => ('A','B'), 'b' => 'B', 1 => 'A' ).antipairs.sort;
    # ((1 => A) => 2 (a => (A B)) => 0 (b => B) => 1)
    
    say ( 'a', 'b', 'c' ).antipairs;
    # (a => 0 b => 1 c => 2)
    
  2. It could go through each of the Pairs in the list like it currently does.

    say ( 'a' => ('A','B'), 'b' => 'B', 1 => 'A' ).invert.sort
    (A => 1 A => a B => a B => b)
    

Since .antipairs already works like .pairs except the opposite, there is really no reason for .invert to also work like it. That would have also made .invert less like a Pair method.

This also has the nice effect that you can get the Pairs from a Hash as a list then call .invert on it, and it will work like just calling .invert on the Hash directly.

say %( 'a' => ('A','B'), 'b' => 'B', 1 => 'A' ).invert.sort;
# (A => 1 A => a B => a B => b)

say %( 'a' => ('A','B'), 'b' => 'B', 1 => 'A' ).list.invert.sort;
# (A => 1 A => a B => a B => b)

It also means that you can call .invert several times and it stays consistent.

say %( 'a' => ('A','B'), 'b' => 'B', 1 => 'A' ).invert.invert.invert.sort;
# (A => 1 A => a B => a B => b)
Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129