canrun/core/
state.rs

1use itertools::Itertools;
2
3use super::mkmvmap::MKMVMap;
4
5use super::constraints::Constraint;
6use crate::{
7    core::{AnyVal, Fork, Unify, Value, VarId},
8    LVarList, ReadyState,
9};
10use std::rc::Rc;
11
12/** The core struct used to contain and manage [`Value`] bindings.
13
14An open [State] can be updated in a few different ways. Most update methods
15return an `Option<State>` to reflect the fact each new constraint can
16invalidate the state. This gives you the ability to quickly short circuit with the
17[`?` operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator)
18as soon the state hits a dead end.
19
20A [`State`] is designed to be cheap to `clone()`, so make a copy if you want
21to try multiple paths.
22
23In general, it is most ergonomic to manipulate a state inside a function
24that returns an `Option<State>` to allow the use of the question mark
25operator (Note that the [`.apply()`](State::apply()) function makes it easy
26to do this).
27
28```
29use canrun::{State, Value};
30
31fn my_fn() -> Option<State> {
32    let x = Value::var();
33    let y = Value::var();
34    let state = State::new();
35    let maybe: Option<State> = state.unify(&x, &Value::new(1));
36    maybe?.unify(&x, &y)
37}
38assert!(my_fn().is_some());
39```
40*/
41#[derive(Clone)]
42pub struct State {
43    pub(crate) values: im_rc::HashMap<VarId, AnyVal>,
44    pub(crate) forks: im_rc::Vector<Rc<dyn Fork>>,
45    constraints: MKMVMap<VarId, Rc<dyn Constraint>>,
46}
47
48impl State {
49    /**
50    Create a new, empty state.
51
52    This often does not need to be used directly as you can
53    [`.query()`](crate::Query::query()) a [`Goal`](crate::goals::Goal)
54    directly, which handles the state creation internally.
55
56    However, there are use cases for creating and managing a state
57    independently of any goals.
58
59    # Example:
60    ```
61    use canrun::{State};
62    let state = State::new();
63    ```
64    */
65    pub fn new() -> Self {
66        State {
67            values: im_rc::HashMap::new(),
68            forks: im_rc::Vector::new(),
69            constraints: MKMVMap::new(),
70        }
71    }
72
73    /**
74    Apply an arbitrary function to a state.
75
76    This is primarily a helper to make it easier to get into a function
77    where you can use the question mark operator while applying multiple
78    updates to a state.
79
80    # Example:
81    ```
82    use canrun::{State, Query, Value};
83
84    let state = State::new();
85    let x = Value::var();
86    let state = state.apply(|s| {
87        s.unify(&x, &Value::new(1))?
88         .unify(&Value::new(1), &x)
89    });
90    let results: Vec<_> = state.query(x).collect();
91    assert_eq!(results, vec![1]);
92    ```
93    */
94    pub fn apply<F>(self, func: F) -> Option<Self>
95    where
96        F: Fn(Self) -> Option<Self>,
97    {
98        func(self)
99    }
100
101    /** Recursively resolve a [`Value`] as far as the currently
102    known variable bindings allow.
103
104    This will return either the final [`Value::Resolved`] (if found) or the
105    last [`Value::Var`] it attempted to resolve. It will not force
106    [`forks`](State::fork()) to enumerate all potential states, so potential
107    bindings that may eventually become confirmed are not considered. Use
108    [`StateIterator::into_states`](super::state_iterator::StateIterator::into_states)
109    if you want to attempt resolving against all (known) possible states.
110
111    # Example:
112    ```
113    use canrun::{State, Query, Value};
114
115    # fn test() -> Option<()> {
116    let state = State::new();
117
118    let x = Value::var();
119    assert_eq!(state.resolve(&x), x);
120
121    let state = state.unify(&x, &Value::new(1))?;
122    assert_eq!(state.resolve(&x), Value::new(1));
123    # Some(())
124    # }
125    # test();
126    ```
127    */
128    pub fn resolve<T: Unify>(&self, val: &Value<T>) -> Value<T> {
129        resolve_any(&self.values, &val.to_anyval())
130            .to_value()
131            // I think this should be safe, so long as we are careful to only
132            // store a var with the correct type internally.
133            .expect("AnyVal resolved to unexpected Value<T>")
134    }
135
136    /**
137    Attempt to [unify](crate::Unify) two values with each other.
138
139    If the unification fails, [`None`](std::option::Option::None) will be
140    returned. [`Value::Var`]s will be checked against relevant
141    [constraints](State::constrain), which can also cause a state to fail.
142
143    # Examples:
144
145    ```
146    use canrun::{State, Query, Value};
147
148    let x = Value::var();
149
150    let state = State::new();
151    let state = state.unify(&x, &Value::new(1));
152    assert!(state.is_some());
153    ```
154
155    ```
156    # use canrun::{State, Query, Value};
157    let state = State::new();
158    let state = state.unify(&Value::new(1), &Value::new(2));
159    assert!(state.is_none());
160    ```
161    */
162    pub fn unify<T: Unify>(mut self, a: &Value<T>, b: &Value<T>) -> Option<Self> {
163        let a = self.resolve(a);
164        let b = self.resolve(b);
165
166        match (a, b) {
167            (Value::Resolved(a), Value::Resolved(b)) => Unify::unify(self, a, b),
168            (Value::Var(a), Value::Var(b)) if a == b => Some(self),
169            (Value::Var(key), value) | (value, Value::Var(key)) => {
170                // TODO: Add occurs check?
171                self.values.insert(key.id, value.to_anyval());
172
173                // check constraints matching newly assigned lvar
174                if let Some(constraints) = self.constraints.extract(&key.id) {
175                    constraints
176                        .into_iter()
177                        .try_fold(self, |state, func| state.constrain(func))
178                } else {
179                    Some(self)
180                }
181            }
182        }
183    }
184
185    /**
186    Add a constraint to the store that can be reevaluated as variables are resolved.
187
188    Some logic is not easy or even possible to express until the resolved
189    values are available. `.constrain()` provides a low level way to run
190    custom imperative code whenever certain bindings are updated.
191
192    See the [`Constraint` trait](crate::core::constraints::Constraint) for more usage information.
193    */
194    pub fn constrain(mut self, constraint: Rc<dyn Constraint>) -> Option<Self> {
195        match constraint.attempt(&self) {
196            Ok(resolve) => resolve(self),
197            Err(watch) => {
198                self.constraints.add(watch.0, constraint);
199                Some(self)
200            }
201        }
202    }
203
204    /**
205    Add a potential fork point to the state.
206
207    If there are many possibilities for a certain value or set of values,
208    this method allows you to add a [`Fork`] object that can enumerate those
209    possible alternate states.
210
211    While this is not quite as finicky as
212    [`Constraints`](State::constrain()), you still probably want to use the
213    [`any`](crate::goals::any!) or [`either`](crate::goals::either()) goals.
214
215    [Unification](State::unify()) is performed eagerly as soon as it is
216    called. [Constraints](State::constrain()) are run as variables are
217    resolved. Forking is executed lazily at the end, when
218    [`StateIterator::into_states`](super::state_iterator::StateIterator::into_states)
219    or [`.query()`](crate::Query::query()) is called.
220    */
221    pub fn fork(mut self, fork: impl Fork) -> Option<Self> {
222        self.forks.push_back(Rc::new(fork));
223        Some(self)
224    }
225
226    /**
227    Generate a list of [`LVar`](crate::LVar)s in this state. This takes into account bound variables
228    and constraint watches.
229    */
230    pub fn vars(&self) -> LVarList {
231        let vars = self.values.keys();
232        let watched_ids = self.constraints.keys();
233        let ids: Vec<_> = vars.chain(watched_ids).unique().copied().collect();
234        LVarList(ids)
235    }
236
237    /** Returns `true` if the `State` has no open forks or constraints.
238
239    If ready, then a [`ReadyState`] can be derived with [`State::ready()`]. */
240    pub fn is_ready(&self) -> bool {
241        self.forks.is_empty() && self.constraints.is_empty()
242    }
243    /** Returns a [`ReadyState`] if the `State` has no open forks or constraints. */
244    pub fn ready(self) -> Option<ReadyState> {
245        if self.is_ready() {
246            Some(ReadyState::new(self.values))
247        } else {
248            None
249        }
250    }
251}
252
253pub(crate) fn resolve_any<'a>(
254    values: &'a im_rc::HashMap<VarId, AnyVal>,
255    val: &'a AnyVal,
256) -> &'a AnyVal {
257    match val {
258        AnyVal::Var(unresolved) => {
259            let resolved = values.get(unresolved);
260            match resolved {
261                Some(AnyVal::Var(found_var)) if found_var == unresolved => val,
262                Some(found) => resolve_any(values, found),
263                None => val,
264            }
265        }
266        value @ AnyVal::Resolved(_) => value,
267    }
268}
269
270impl Default for State {
271    fn default() -> Self {
272        Self::new()
273    }
274}
275
276#[cfg(test)]
277mod test {
278    use crate::{
279        core::{LVar, Query, StateIter, StateIterator, Value},
280        goals::{assert_1, Goal},
281    };
282
283    use super::*;
284
285    #[test]
286    fn state_default() {
287        let state = State::default();
288        assert!(state.is_ready());
289    }
290
291    #[test]
292    fn basic_unify() {
293        let x = Value::var();
294        let state = State::new();
295        let state = state.unify(&x, &Value::new(1)).unwrap();
296        assert_eq!(state.resolve(&x), Value::new(1));
297    }
298
299    #[test]
300    fn basic_fork() {
301        let x = LVar::new();
302        let state: State = State::new();
303        let forked = state.fork(move |s: &State| -> StateIter {
304            let s1 = s.clone().unify(&x.into(), &Value::new(1));
305            let s2 = s.clone().unify(&x.into(), &Value::new(2));
306            Box::new(s1.into_iter().chain(s2.into_iter()))
307        });
308        assert!(forked.clone().unwrap().ready().is_none());
309        let results = forked
310            .into_states()
311            .map(|s| s.resolve(&x.into()))
312            .collect::<Vec<_>>();
313        assert_eq!(results, vec![Value::new(1), Value::new(2)]);
314    }
315
316    #[test]
317    fn basic_apply() {
318        let x = LVar::new();
319        let state: State = State::new();
320        let results: Vec<_> = state
321            .apply(move |s| s.unify(&x.into(), &1.into()))
322            .query(x)
323            .collect();
324        assert_eq!(results, vec![1]);
325    }
326
327    #[test]
328    fn unify_vars() {
329        let x = LVar::new();
330        let state: State = State::new();
331        let results = state
332            .apply(move |s| s.unify(&x.into(), &1.into()))
333            .unwrap()
334            .vars();
335        assert_eq!(results.0, vec![x.id]);
336    }
337
338    #[test]
339    fn constraint_vars() {
340        let x: LVar<usize> = LVar::new();
341        let state: State = State::new();
342        let results = assert_1(x, |x| *x == 1).apply(state).unwrap().vars();
343        assert_eq!(results.0, vec![x.id]);
344    }
345}