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}