proto_vulcan/operator/
everyg.rs

1//! # For-operator
2//!
3//! For the same effect as miniKanren's `everyg`, proto-vulcan uses the `for`-operator, which
4//! ensures that a goal `g` succeeds for all `x` in collection `coll`. The collection must be such
5//! that it implements `IntoIterator<Item = &LTerm>`.
6//! ```ignore
7//! for x in &coll {
8//!     g
9//! }
10//!
11//! ```
12use crate::engine::Engine;
13use crate::goal::{AnyGoal, InferredGoal};
14use crate::lterm::LTerm;
15use crate::operator::conj::InferredConj;
16use crate::operator::ForOperatorParam;
17use crate::solver::{Solve, Solver};
18use crate::state::State;
19use crate::stream::Stream;
20use crate::user::User;
21use std::fmt::Debug;
22use std::rc::Rc;
23
24pub struct Everyg<T, U, E, G>
25where
26    U: User,
27    E: Engine<U>,
28    G: AnyGoal<U, E>,
29    T: Debug + 'static,
30    for<'a> &'a T: IntoIterator<Item = &'a LTerm<U, E>>,
31{
32    coll: T,
33    g: Box<dyn Fn(LTerm<U, E>) -> G>,
34}
35
36impl<T, U, E, G> Debug for Everyg<T, U, E, G>
37where
38    U: User,
39    E: Engine<U>,
40    G: AnyGoal<U, E>,
41    T: Debug + 'static,
42    for<'a> &'a T: IntoIterator<Item = &'a LTerm<U, E>>,
43{
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        write!(f, "Everyg()")
46    }
47}
48
49impl<T, U, E, G> Everyg<T, U, E, G>
50where
51    U: User,
52    E: Engine<U>,
53    G: AnyGoal<U, E>,
54    T: Debug + 'static,
55    for<'a> &'a T: IntoIterator<Item = &'a LTerm<U, E>>,
56{
57    fn new(coll: T, g: Box<dyn Fn(LTerm<U, E>) -> G>) -> InferredGoal<U, E, G> {
58        InferredGoal::new(G::dynamic(Rc::new(Everyg { coll, g })))
59    }
60}
61
62impl<T, U, E, G> Solve<U, E> for Everyg<T, U, E, G>
63where
64    U: User,
65    E: Engine<U>,
66    G: AnyGoal<U, E>,
67    T: Debug + 'static,
68    for<'a> &'a T: IntoIterator<Item = &'a LTerm<U, E>>,
69{
70    fn solve(&self, solver: &Solver<U, E>, state: State<U, E>) -> Stream<U, E> {
71        let term_iter = IntoIterator::into_iter(&self.coll);
72        let goal_iter = term_iter.map(|term| (*self.g)(term.clone()));
73        InferredConj::from_iter(goal_iter).goal.solve(solver, state)
74    }
75}
76
77pub fn everyg<T, U, E, G>(param: ForOperatorParam<T, U, E, G>) -> InferredGoal<U, E, G>
78where
79    U: User,
80    E: Engine<U>,
81    G: AnyGoal<U, E>,
82    T: Debug + 'static,
83    for<'a> &'a T: IntoIterator<Item = &'a LTerm<U, E>>,
84{
85    Everyg::new(param.coll, param.g)
86}