mini_kanren/goals/
hashmap.rs

1use crate::core::structure::Structure;
2use crate::{Substitution, Value, Var};
3use std::any::Any;
4use std::collections::HashMap;
5use std::fmt::Debug;
6use std::hash::Hash;
7use std::sync::Arc;
8
9#[macro_export]
10macro_rules! hashmap {
11    () => {
12        std::collections::HashMap::new()
13    };
14}
15
16impl<T: 'static + Debug + Eq + Hash> Structure for HashMap<T, Value> {
17    fn occurs<'s>(&self, _x: &Var, _s: &Substitution<'s>) -> bool {
18        //s.occurs(x, &self.first) || s.occurs(x, &self.second)
19        unimplemented!()
20    }
21
22    fn unify<'s>(&self, v: &Value, mut s: Substitution<'s>) -> Option<Substitution<'s>> {
23        let other = v.downcast_ref::<Self>()?;
24        for (_, v1, v2) in double_iterator(self, other) {
25            s = s.unify(v1?, v2?)?;
26        }
27        Some(s)
28    }
29
30    fn walk_star(self: Arc<Self>, _s: &Substitution<'_>) -> Value {
31        //(s.walk_star(&self.first), s.walk_star(&self.second)).into()
32        unimplemented!()
33    }
34
35    fn reify_s<'s>(&self, _s: Substitution<'s>) -> Substitution<'s> {
36        //s.reify_s(&self.first).reify_s(&self.second)
37        unimplemented!()
38    }
39
40    fn as_any(&self) -> &dyn Any {
41        self
42    }
43
44    fn eqv(&self, other: &Value) -> bool {
45        other
46            .downcast_ref::<Self>()
47            .map(|v| double_iterator(self, v).all(|(_, v1, v2)| v1 == v2))
48            .unwrap_or(false)
49    }
50}
51
52fn double_iterator<'a, K: Eq + Hash, V>(
53    first: &'a HashMap<K, V>,
54    second: &'a HashMap<K, V>,
55) -> impl Iterator<Item = (&'a K, Option<&'a V>, Option<&'a V>)> {
56    let keys_in_first = first.iter().map(move |(k, v)| (k, Some(v), second.get(k)));
57    let keys_only_in_second = second
58        .iter()
59        .filter(move |(k, _)| !first.contains_key(k))
60        .map(|(k, v)| (k, None, Some(v)));
61
62    keys_in_first.chain(keys_only_in_second)
63}
64
65#[cfg(test)]
66mod tests {
67    use crate::core::value::Value;
68    use crate::testing::has_unique_solution;
69    use crate::*;
70    use std::collections::HashMap;
71
72    #[test]
73    fn two_empty_hashmaps_are_unifiable() {
74        let a: HashMap<(), Value> = hashmap![];
75        let b: HashMap<(), Value> = hashmap![];
76        has_unique_solution(run!(q, eq(a, b)), Value::rv(0));
77    }
78}