Skip to main content

mini_kanren/core/
pair.rs

1use crate::core::logic_variable::Var;
2use crate::core::structure::Structure;
3use crate::core::substitution::Substitution;
4use crate::core::value::Value;
5use std::any::Any;
6use std::fmt::{Debug, Formatter, Result};
7use std::sync::Arc;
8
9#[derive(Clone, PartialEq)]
10pub struct Pair {
11    pub first: Value,
12    pub second: Value,
13}
14
15impl Debug for Pair {
16    fn fmt(&self, f: &mut Formatter) -> Result {
17        if !f.alternate() {
18            write!(f, "(")?;
19        }
20
21        if self.second.downcast_ref::<()>().is_some() {
22            write!(f, "{:?}", self.first)?;
23        } else if let Some(next) = self.second.downcast_ref::<Pair>() {
24            write!(f, "{:?} {:#?}", self.first, next)?;
25        } else {
26            write!(f, "{:?} . {:?}", self.first, self.second)?;
27        }
28
29        if !f.alternate() {
30            write!(f, ")")?;
31        }
32
33        Ok(())
34    }
35}
36
37impl Structure for Pair {
38    fn occurs<'s>(&self, x: &Var, s: &Substitution<'s>) -> bool {
39        s.occurs(x, &self.first) || s.occurs(x, &self.second)
40    }
41
42    fn unify<'s>(&self, v: &Value, s: Substitution<'s>) -> Option<Substitution<'s>> {
43        let other = v.downcast_ref::<Self>()?;
44        s.unify(&self.first, &other.first)
45            .and_then(|s| s.unify(&self.second, &other.second))
46    }
47
48    fn walk_star(self: Arc<Self>, s: &Substitution<'_>) -> Value {
49        (s.walk_star(&self.first), s.walk_star(&self.second)).into()
50    }
51
52    fn reify_s<'s>(&self, s: Substitution<'s>) -> Substitution<'s> {
53        s.reify_s(&self.first).reify_s(&self.second)
54    }
55
56    fn as_any(&self) -> &dyn Any {
57        self
58    }
59
60    fn eqv(&self, other: &Value) -> bool {
61        other
62            .downcast_ref::<Self>()
63            .map(|v| v == self)
64            .unwrap_or(false)
65    }
66}
67
68impl From<(Value, Value)> for Pair {
69    fn from(pair: (Value, Value)) -> Self {
70        Pair {
71            first: pair.0,
72            second: pair.1,
73        }
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn pairs_print_two_values_in_parentheses_separated_by_dot() {
83        let first = Value::new(());
84        let second = Value::new(2);
85        let pair = Pair { first, second };
86
87        let repr = format!("{:?}", pair);
88
89        assert_eq!(repr, "(() . 2)")
90    }
91
92    #[test]
93    fn pairs_print_only_first_value_in_parentheses_if_second_is_nil() {
94        let first = Value::new(1);
95        let second = Value::new(());
96        let pair = Pair { first, second };
97
98        let repr = format!("{:?}", pair);
99
100        assert_eq!(repr, "(1)")
101    }
102
103    #[test]
104    fn pairs_print_as_list_if_second_is_pair() {
105        let a = Value::new(1);
106        let b = Value::new(2);
107        let c = Value::new(3);
108        let pair = Pair {
109            first: a,
110            second: Value::new(Pair {
111                first: b,
112                second: c,
113            }),
114        };
115
116        let repr = format!("{:?}", pair);
117
118        assert_eq!(repr, "(1 2 . 3)")
119    }
120
121    #[test]
122    fn pairs_print_alternate_omits_parentheses() {
123        let first = Value::new(());
124        let second = Value::new(2);
125        let pair = Pair { first, second };
126
127        let repr = format!("{:#?}", pair);
128
129        assert_eq!(repr, "() . 2")
130    }
131}