Patrick R. Michaud wrote:
> The continuing exchanges regarding junctions, and the ongoing tendency
> by newcomers to think of them and try to use them as sets, makes
> me feel that it might be worthwhile to define and publish a standard
> C<Set> class and operations sooner rather than later in Perl 6

I agree.  See pugs/ext/Set.

It presents a set-like interface to Junctions.

eg,

  use Set;

  my $low = set( 0..4 );
  my $odd = set( (0..4).map:{ $_ * 2 + 1 } );

  say ($low ∩ $odd).members.join(",");  # 1,3
  say ($low ∪ $odd).members.join(",");  # 0,1,2,3,4,5,7,9

  # difference - not this is not a backslash, it's U+2216
  say ($low ∖ $odd).members.join(",");  # 0,2,4
  say ($odd ∖ $low).members.join(",");  # 5,7,9

  # symmetric difference - union of the above
  say ($low % $odd).members.join(",");  # 0,2,4,5,7,9

  # test for membership
  say $low ∋ 4;   # true
  say $low ∌ 5;   # true
  say $odd ∋ 4;   # false
  say $odd ∌ 5;   # false

  # set relations
  say ( $low ∪ $odd ) ⊇ $low;   # true

Well, actually the above doesn't work yet.  But there are ASCII versions
and english methods for those that like coding something that actually
works today ;).

Here's a directed graph traversal that handle cycles correctly; this is
largely why I'd like to see a common Role to all containers... so that
.values can be expected to DTRT.  OTOH, maybe Maps with object keys would
"miss out" in this algorithm so another method name is more appropriate.

  use Set;
  my @stack = ($root);
  my $seen = set(@stack);

  while (my $item = shift @stack) {
      # do something with $item

      if $item.can("values") {
          push @stack, $item.values.grep:{ $seen.insert($_) };
      }
  }

Caveats for the above probably abound, but you get the picture.

Note that the Set::Object module for Perl 5 is useful for the same thing
(assumes that $root is a ref):

  use Set::Object qw(set);
  use Scalar::Util qw(reftype blessed);
  use Perl6::Junction qw(any);
  my @stack = ($root);
  my $seen = set(@stack);

  while (my $item = shift @stack) {
      # do something with $item

      if (blessed $item and $item->can("members")) {
          push @stack, grep { ref $_ && $seen->insert($_) } $item->members;
      }
      if (reftype $item eq "HASH") {
          push @stack, grep { ref $_ && $seen->insert($_) } values %$item;
      }
      elsif (reftype $item eq "ARRAY") {
          push @stack, grep { ref $_ && $seen->insert($_) } @$item;
      }
      elsif (reftype $item eq any(qw(REF SCALAR)) ) {
          push @stack, $$item if $seen->insert($$item);
      }
  }

As you can see, this sort of thing ends up an anti-design pattern.

Sam.

Reply via email to