develooper Front page | perl.perl6.language | Postings from March 2005

SEND + MORE = MONEY (works now in pugs with junctions!)

Thread Previous | Thread Next
From:
Sam Vilain
Date:
March 10, 2005 23:38
Subject:
SEND + MORE = MONEY (works now in pugs with junctions!)
Message ID:
42314ACE.3040906@vilain.net
Rod Adams wrote:
> And as one who recently proposed a way of getting Prolog like features 
> in Perl (through Rules, not Junctions), I understand the appeal 
> completely. Junctions are not the way to that goal. They are something 
> different.
 > Taking multiple values at once is what junctions are all about.
 > People seem to forget the role the predicate plays in junction
 > evaluation. You thread over the different values, gain a result, and
 > then use the predicate to recombine the results into a single scalar.
 > That assumption is in err, and the example does not generate the
 > solutions desired

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>).

However, the former keeps the optimisation out of the algorithm, so that
when someone comes along later with a nice grunty optimiser there is more
chance that it gets a go at the entire solution space rather than having
to fall back to exhaustive searching.

(which might have to find ways to prove associativity of &&, etc, to make
`real' optimisations).

I'm trying to see a way that these two ways of using junctions are
compatible.  As I see it, people want to stretch out the time that the
junction is "true", to something non-zero, without having to explicitly
create all those closures.

Getting the old behaviour would be easy, just set a variable in the `if'
clause:

   my $j1 = any(1..5);
   my $j2 = any(5..9);

   my $they_equal;
   if ($j1 == $j2) {
       # intersection of sets - $j1 and $j2 are any(5), any(5)
       $they_equal = 1;
   } else {
       # symmetric difference of sets - $j1 and $j2 are now
       #   any(1..5), any(5..9) (where $j1 != $j2 :))

   }

   if ($they_equal) {

   }

Now, the `where $j1 != $j2' bit there, which looks like it's on crack, is
a way of representing that instead of actually calling that second branch
24 times, it could be calling it with two junctions which are `entangled'
(or, if you prefer, `outer joined').  $j1 and $j2 appear almost untouched
- except any test that uses $j1 and $j2 together will not see the
combination of ($j1 == 5) and ($j2 == 5).

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);
   }

$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?

One last thing - that comment about any(@foo) == one(@foo) not
checking for uniqueness in a list is right - the correct version
is:

   all(@foo) == one(@foo)

Sam.

Footnotes:
  * - any relational database `experts' who want to remind me of which
      normalisation form rules this breaks, please remember that RDBMSes
      and normalised forms approximate Set Theory, which this is trying to
      do as well, so I believe such discussion is irrelevant.



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