cut over to next_proposition using resolved_count
[scpubgit/DX.git] / lib / DX / Hypothesis.pm
1 package DX::Hypothesis;
2
3 use DX::ActionPolicy::LockScope;
4 use Types::Standard qw(ArrayRef);
5 use DX::Utils qw(deparse);
6 use DX::Class;
7
8 has scope => (is => 'ro', isa => Scope, required => 1);
9
10 has resolved_propositions => (
11   is => 'ro', isa => ResolvedPropositionSet, required => 1
12 );
13
14 has outstanding_propositions => (
15   is => 'ro', isa => ArrayRef[Proposition], required => 1
16 );
17
18 has actions => (
19   is => 'ro', isa => ArrayRef[Action], required => 1
20 );
21
22 has action_applications => (
23   is => 'ro', isa => ArrayRef[Action], required => 1
24 );
25
26 has action_policy => (is => 'ro', isa => ActionPolicy, required => 1);
27
28 sub with_actions {
29   my ($self, @actions) = @_;
30   my $hyp = $self;
31   foreach my $act (@actions) {
32     return undef unless $self->action_policy->allows($act);
33     ($hyp, my @events) = $act->dry_run($hyp);
34     return undef unless $hyp;
35     $hyp = $hyp->but_recheck_for(@events);
36     return undef unless $hyp;
37   }
38   return $hyp;
39 }
40
41 sub but_recheck_for {
42   my ($self, @events) = @_;
43   my ($still_resolved, @recheck) = $self->resolved_propositions
44                                         ->but_expire_for(@events);
45   return $self unless @recheck;
46
47   my $ap = DX::ActionPolicy::LockScope->new(
48     lock_to_depth => $self->scope->depth,
49     next_policy => $self->action_policy,
50   );
51
52   # we should probably be doing something about pruning the scope
53   # but that's completely pointless until we have rules
54
55   my $hyp = ref($self)->new(
56     scope => $self->scope,
57     resolved_propositions => DX::ResolvedPropositionSet->new_empty,
58     outstanding_propositions => \@recheck,
59     actions => [],
60     action_applications => [],
61     action_policy => $ap,
62   );
63
64   my $pseq = DX::PropositionSequence->new(
65     members => \@recheck,
66     external_names => {},
67     internal_names => {},
68   );
69
70   trace 'step.recheck.hyp' => $hyp;
71
72   my $ss = DX::SearchState->new_for($hyp, $pseq);
73
74   my $sol_ss = $ss->find_solution;
75
76   unless ($sol_ss) {
77     trace 'step.recheck.fail' => 'argh';
78     return undef;
79   }
80
81   my $sol_rps = $sol_ss->current_hypothesis->resolved_propositions;
82
83   my $rps = $still_resolved;
84
85   $rps = $rps->with_updated_dependencies_for(
86     $_, $sol_rps->dependencies_for($_)
87   ) for @recheck;
88
89   trace 'step.recheck.done' => 'yay';
90
91   return $self->but(resolved_propositions => $rps);
92 }
93
94 sub resolve_head_dependent_on {
95   my ($self, $depends) = @_;
96   my ($first, @rest) = @{$self->outstanding_propositions};
97   $self->but(
98     resolved_propositions => $self->resolved_propositions
99                                   ->with_resolution_for(
100                                       $first,
101                                       $depends,
102                                     ),
103     outstanding_propositions => \@rest,
104   );
105 }
106
107 1;