switch SearchState to using Backtrack step
[scpubgit/DX.git] / lib / DX / SearchState.pm
1 package DX::SearchState;
2
3 use Types::Standard qw(Maybe);
4 use DX::Step::Backtrack;
5 use DX::Step::InvokeNextPredicate;
6 use DX::Class;
7
8 has current_hypothesis => (is => 'ro', isa => Hypothesis, required => 1);
9
10 has next_step => (is => 'ro', isa => Maybe[Step]);
11
12 has propositions => (is => 'ro', isa => PropositionSequence, required => 1);
13
14 has alternatives => (is => 'ro', isa => AlternativeList, required => 1);
15
16 sub next_proposition {
17   my ($self, $hyp) = @_;
18   $hyp ||= $self->current_hypothesis;
19   $self->propositions->members->[
20     $hyp->resolved_propositions->resolved_count
21   ];
22 }
23
24 sub new_for {
25   my ($class, $hyp, $props) = @_;
26   $class->new(
27     current_hypothesis => $hyp,
28     alternatives => [],
29     next_step => DX::Step::InvokeNextPredicate->new(
30       proposition => $props->members->[0],
31     ),
32     propositions => $props,
33   );
34 }
35
36 sub with_one_step {
37   my ($self) = @_;
38   my $hyp = $self->current_hypothesis;
39   return undef unless my $step = $self->next_step;
40   my ($new_ss) = $step->apply_to($self);
41   return $new_ss if $new_ss;
42   my ($first_alt, @rest_alt) = @{$self->alternatives};
43   return undef unless $first_alt;
44   trace 'search.backtrack.rewind_to' => $first_alt->[1];
45   return $self->but(
46     next_step => DX::Step::Backtrack->new,
47   );
48 }
49
50 sub force_backtrack {
51   my ($self) = @_;
52   my ($first_alt, @rest_alt) = @{$self->alternatives};
53   return undef unless $first_alt;
54   trace 'search.backtrack.forced' => $first_alt->[0];
55   return ref($self)->new(
56     current_hypothesis => $first_alt->[0],
57     next_step => $first_alt->[1],
58     alternatives => \@rest_alt,
59     propositions => $self->propositions,
60   );
61 }
62
63 1;