Sam Vilain wrote:


I've changed examples/sendmoremoney.p6 in the pugs distribution to use junctions correctly to demonstrate that they *can* be used to solve these sorts of problems, and that it is just a matter of semantics and writing code correctly.

However, poor semantics can make the task of writing optimisers
unnecessarily difficult or impractical, as Bourne demonstrated.

in short, it seems people want this:

  my $a = any(1..9);
  my $b = any(1..9);
  my $c = any(0..9);

  if ( $a != $b && $b != $c && $a != $c &&
       ($a + $b == $a * 10 + $c) ) {
      print "$a + $b = $a$c";
  }

To mean this (forgive the duplication of collapse() here):

  sub collapse($x, $sub) { $sub.($x) }
  sub collapse($x, $y, $sub) { $sub.($x,$y) }

  my $a = any(1..9);
  my $b = any(1..9);
  my $c = any(0..9);

  collapse($a, $b, -> $a, $b {
      ($a != $b) &&
      collapse($c, -> $c {
          if ( ( $b != $c ) && ( $a != $c ) &&
               ($a + $b == $a * 10 + $c) ) {
              say "$a + $b = $a$c";
          }
      });
  });

(and YES THAT WORKS <g>).

Yes, it does work, given the current state of autothreading.
Well, you'd need a C< use junctions; > in order to store a junction in a variable. And I'm not certain if that changes the autothreading behavior of the closures or not. You might have to declare the collapses as:


multi sub collapse ($x is none(Junction), $sub) {...};
multi sub collapse ($x is none(Junction), $y is none(Junction), $sub) {...};


to get it to thread correctly. I'm not sure. (Pretty sure you'd need the 'multi' in there).



It's also a perfect example of where my hyperthreader operator (it hasn't been nailed down yet what the exact syntax is (or even if it exists), I'm waiting for Damian to get back to continue that thread.) is a better tool than junctions. Assuming we use my »« syntax, SEND+MORE==MONEY could be written as:
sub test ($s, $e, $n, $d, $m, $o, $r, $y) {
if "$s$e$n$d" + "$m$o$r$e" == "$m$o$n$e$y" &&
all($s,$e,$n,$d,$m,$o,$r,$y) == one($s,$e,$n,$d,$m,$o,$r,$y)
{
say "$s$e$n$d + $m$o$r$e == $m$o$n$e$y";
}
}


   test(»1..9«, »0..9«, »0..9«, »0..9«, »1..9«, »0..9«, »0..9«, »0..9«);

Using Damian's every() syntax, the last line becomes:

   test(every(1..9), every(0..9), every(0..9), every(0..9),
        every(1..9), every(0..9), every(0..9), every(0..9));

It's extremely brute force and inefficient, but it works.


I have the philosophical problem with your use of junctions in this context due to the fact that you are completely ignoring the predicate of the junction. The C< all(...) == one(...) > is an excellent use of junctions, that makes use of the predicates when the junctions are evaluated. If you want threading without the predicate, I give you the hyperthreader (well, I'm trying to).



I'll also point out that what you wrote above is a lot more readable as:

   for 1..9 -> $a {
     for 1..9 -> $b {
       next unless $b == none($a);
       for 0..9 -> $c {
         next unless $c == none($a, $b);
         if $a + $b == $a * 10 + $c {
           say "$a + $b = $a$c"
         }
       }
     }
   }


I mean, wouldn't it really be nice if you could write stuff like this:

  my @users is persistent("users.isam");
  my @accounts is persistent("accounts.isam");

  my $r_user = any(@user);
  my $r_account = any(@account);

  if ( $r_account.user == $r_user ) {
      say("That junction is:", $r_user);
  }

I'm fairly certain that I'll be writing a Set class if no one beats me to it.


   use Sets;

my @users is persistent("users.isam");
my @accounts is persistent("accounts.isam");
my $s_validusers = set(@accounts».user) - @users;


   for values $s_validusers -> $user {
     say "$user is a valid user";
   }


$r_user at that point represents only the users which have at least one object in @accounts for which there exists an $r_account with a `user' property that is that $r_user member[*].

The closure would then either be run once, with $r_user still a junction
(if the interpreter/`persistent' class was capable of doing so), or once
for every matching tuple of ($r_account, $r_user). We're still talking in
terms of Set Theory, right?

If you want Set Theory.. use Sets. Or use some form of Logical Programming which builds the sets implicitly for you, and does all the filtering and backtracking you're asking for.


Both topics have been explored recently. The results of that exploration can be summarized as:
- Sets would make a nifty module to have around.
- Integrating Logical Programming into Perl needs a lot more thought and effort than will likely happen before 6.0.0. Modules grafting LP into Perl and/or Parrot are welcome.


-- Rod Adams






Reply via email to