restructure searching so with_one_step is actually one step
Matt S Trout [Sat, 26 Mar 2016 04:32:17 +0000 (04:32 +0000)]
lib/DX/QueryState.pm
lib/DX/SearchState.pm
lib/DX/Step/InvokeNextPredicate.pm [new file with mode: 0644]

index 496b983..f7c030a 100644 (file)
@@ -55,10 +55,7 @@ sub new_search_state_for {
     action_applications => [],
     action_policy => DX::ActionPolicy::Allow->new,
   );
-  return DX::SearchState->new(
-    current_hypothesis => $hyp,
-    alternatives => [],
-  );
+  return DX::SearchState->new_for($hyp);
 }
 
 sub with_additional_proposition {
index 3daca33..1053f48 100644 (file)
@@ -1,11 +1,12 @@
 package DX::SearchState;
 
 use Types::Standard qw(Maybe);
+use DX::Step::InvokeNextPredicate;
 use DX::Class;
 
 has current_hypothesis => (is => 'ro', isa => Hypothesis, required => 1);
 
-has resume_step => (is => 'ro', isa => Maybe[Step]);
+has next_step => (is => 'ro', isa => Maybe[Step]);
 
 has alternatives => (is => 'ro', isa => AlternativeList, required => 1);
 
@@ -14,37 +15,38 @@ sub new_for {
   $class->new(
     current_hypothesis => $hyp,
     alternatives => [],
+    next_step => DX::Step::InvokeNextPredicate->new,
   );
 }
 
 sub with_one_step {
   my ($self) = @_;
   my $hyp = $self->current_hypothesis;
-  my $step = $self->resume_step
-             || $hyp->head_proposition->resolve_for($hyp->scope);
-  my @alt = @{$self->alternatives};
-  HYP: while ($hyp) {
-    STEP: while ($step) {
-      my ($new_hyp, $alt_step) = $step->apply_to($hyp);
-      if ($new_hyp) {
-        return $self->but(
-          current_hypothesis => $new_hyp,
-          alternatives => [
-            ($alt_step
-              ? [ $hyp, $alt_step ]
-              : ()),
-            @alt
-          ],
-          resume_step => undef,
-        );
-      }
-      trace 'search.backtrack.alt' => $alt_step;
-      $step = $alt_step;
-    }
-    ($hyp, $step) = @{shift(@alt)||[]};
-    trace 'search.backtrack.rewind_to' => $step;
+  return undef unless my $step = $self->next_step;
+  my ($first_alt, @rest_alt) = my @alt = @{$self->alternatives};
+  my ($new_hyp, $alt_step) = $step->apply_to($hyp);
+  if ($new_hyp) {
+    return $self->but(
+      current_hypothesis => $new_hyp,
+      alternatives => [
+        ($alt_step
+          ? [ $hyp, $alt_step ]
+          : ()),
+        @alt
+      ],
+      next_step => DX::Step::InvokeNextPredicate->new,
+    );
   }
-  return undef;
+  if ($alt_step) {
+    return $self->but(next_step => $alt_step);
+  }
+  return undef unless $first_alt;
+  trace 'search.backtrack.rewind_to' => $first_alt->[1];
+  return $self->but(
+    current_hypothesis => $first_alt->[0],
+    alternatives => \@rest_alt,
+    next_step => $first_alt->[1],
+  );
 }
 
 sub find_solution {
@@ -63,7 +65,7 @@ sub force_backtrack {
   trace 'search.backtrack.forced' => $first_alt->[0];
   return ref($self)->new(
     current_hypothesis => $first_alt->[0],
-    resume_step => $first_alt->[1],
+    next_step => $first_alt->[1],
     alternatives => \@rest_alt
   );
 }
diff --git a/lib/DX/Step/InvokeNextPredicate.pm b/lib/DX/Step/InvokeNextPredicate.pm
new file mode 100644 (file)
index 0000000..f4a68dd
--- /dev/null
@@ -0,0 +1,12 @@
+package DX::Step::InvokeNextPredicate;
+
+use DX::Class;
+
+with 'DX::Role::Step';
+
+sub apply_to {
+  my ($self, $hyp) = @_;
+  return (undef, $hyp->head_proposition->resolve_for($hyp->scope));
+}
+
+1;