71477e817071b3c3dd1758bec6d3e1aef46171cf
[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_policy => (is => 'ro', isa => ActionPolicy, required => 1);
23
24 sub head_proposition { shift->outstanding_propositions->[0] }
25
26 sub with_actions {
27   my ($self, @actions) = @_;
28   my $hyp = $self;
29   foreach my $act (@actions) {
30     return undef unless $self->action_policy->allows($act);
31     ($hyp, my @events) = $act->dry_run($hyp);
32     return undef unless $hyp;
33     $hyp = $hyp->but_recheck_for(@events);
34     return undef unless $hyp;
35   }
36   return $hyp;
37 }
38
39 sub but_recheck_for {
40   my ($self, @events) = @_;
41   my ($still_resolved, @recheck) = $self->resolved_propositions
42                                         ->but_expire_for(@events);
43   return $self unless @recheck;
44
45   my $ap = DX::ActionPolicy::LockScope->new(
46     lock_to_depth => $self->scope->depth,
47     next_policy => $self->action_policy,
48   );
49
50   # we should probably be doing something about pruning the scope
51   # but that's completely pointless until we have rules
52
53   my $hyp = ref($self)->new(
54     scope => $self->scope,
55     resolved_propositions => DX::ResolvedPropositionSet->new_empty,
56     outstanding_propositions => \@recheck,
57     actions => [],
58     action_policy => $ap,
59   );
60
61   my $ss = DX::SearchState->new_for($hyp);
62
63   return undef unless my $sol_ss = $ss->find_solution;
64
65   my $sol_rps = $sol_ss->current_hypothesis->resolved_propositions;
66
67   my $rps = $still_resolved;
68
69   $rps = $rps->with_updated_dependencies_for(
70     $_, $sol_rps->dependencies_for($_)
71   ) for @recheck;
72
73   return $self->but(resolved_propositions => $rps);
74 }
75
76 sub resolve_head_dependent_on {
77   my ($self, $depends) = @_;
78   my ($first, @rest) = @{$self->outstanding_propositions};
79   $self->but(
80     resolved_propositions => $self->resolved_propositions
81                                   ->with_resolution_for(
82                                       $first,
83                                       $depends,
84                                     ),
85     outstanding_propositions => \@rest,
86   );
87 }
88
89 1;