extract backtrack decisions out into steps
[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   return undef unless my $step = $self->next_step;
39   return $step->apply_to($self);
40 }
41
42 sub force_backtrack {
43   my ($self) = @_;
44   my ($first_alt, @rest_alt) = @{$self->alternatives};
45   return undef unless $first_alt;
46   trace 'search.backtrack.forced' => $first_alt->[0];
47   return ref($self)->new(
48     current_hypothesis => $first_alt->[0],
49     next_step => $first_alt->[1],
50     alternatives => \@rest_alt,
51     propositions => $self->propositions,
52   );
53 }
54
55 1;