rslogic/
goal.rs

1//! # Logical Goals
2//!
3//! Goals are used to specify logical statements.
4
5use state::{Unif, Var, State, PossibleStates};
6use std::marker::PhantomData;
7
8/// Evaluate a `Goal` to produce zero or more `State`s, or
9/// collections of variable bindings.
10pub trait Goal<T> where T: PartialEq + Unif<T> {
11    fn eval(&self, state: &State<T>) -> PossibleStates<T>;
12}
13
14
15/// Evaluating a `Fail` goal always results in zero states.
16pub struct Fail<T> where T: PartialEq + Unif<T> {
17    _m: PhantomData<T>,
18}
19
20impl<T> Goal<T> for Fail<T> where T: PartialEq + Unif<T> {
21    fn eval(&self, _: &State<T>) -> PossibleStates<T> {
22        Vec::with_capacity(0)
23    }
24}
25
26/// Creates a `Fail` goal.
27pub fn fail<T>() -> Fail<T> where T: PartialEq + Unif<T> {
28    Fail { _m: PhantomData }
29}
30
31
32/// Evaluating a `UnifyVal` goal attempts to unify a variable and a value.
33pub struct UnifyVal<T> where T: PartialEq + Unif<T> {
34    var: Var,
35    val: T,
36}
37
38impl<T> Goal<T> for UnifyVal<T> where T: Clone + Eq + Unif<T> {
39    fn eval(&self, state: &State<T>) -> PossibleStates<T> {
40        state.unify_val(&self.var, self.val.clone())
41    }
42}
43
44/// Creates a `UnifyVal` goal that attempts to unify the variable and the value.
45pub fn unify_val<T>(var: &Var, val: T) -> UnifyVal<T> where T: PartialEq + Unif<T> {
46    UnifyVal { var: *var, val: val }
47}
48
49
50/// Evaluating a `UnifyVar` goal attempts to unify the variables.
51pub struct UnifyVar<T> where T: PartialEq + Unif<T> {
52    v1: Var,
53    v2: Var,
54    _m: PhantomData<T>,
55}
56
57impl<T> Goal<T> for UnifyVar<T> where T: PartialEq + Unif<T> {
58    fn eval(&self, state: &State<T>) -> PossibleStates<T> {
59        state.unify_var(&self.v1, &self.v2)
60    }
61}
62
63/// Creates a `UnifyVar` goal that attempts to unify the variables.
64pub fn unify_vars<T>(v1: &Var, v2: &Var) -> UnifyVar<T> where T: PartialEq + Unif<T> {
65    UnifyVar { v1: *v1, v2: *v2, _m: PhantomData }
66}
67
68
69/// A `Conjunction` goal evaluates its sub-goal `a` using a given state,
70/// then evaluates sub-goal `b` using the results.
71pub struct Conjunction<T, A, B> where T: PartialEq + Unif<T>, A: Goal<T>, B: Goal<T> {
72    a: A,
73    b: B,
74    _m: PhantomData<T>,
75}
76
77impl<T, A, B> Goal<T> for Conjunction<T, A, B> where T: PartialEq + Unif<T>, A: Goal<T>, B: Goal<T> {
78    fn eval(&self, state: &State<T>) -> PossibleStates<T> {
79        let ra = self.a.eval(state);
80        let mut result : Vec<State<T>> = Vec::with_capacity(0);
81        for s in ra {
82            let mut rb = self.b.eval(&s);
83            result.append(&mut rb);
84        }
85        result
86    }
87}
88
89/// Creates a `Conjunction` goal which returns the conjunction (logical AND) of evaluating the two sub-goals.
90pub fn conj<T, A, B>(a: A, b: B) -> Conjunction<T, A, B> where T: PartialEq + Unif<T>, A: Goal<T>, B: Goal<T> {
91    Conjunction { a: a, b: b, _m: PhantomData }
92}
93
94
95/// Evaluating a `Disjunction` goal returns all the possible states of evaluating `a` and `b`.
96pub struct Disjunction<T, A, B> where T: PartialEq + Unif<T>, A: Goal<T>, B: Goal<T> {
97    a: A,
98    b: B,
99    _m: PhantomData<T>,
100}
101
102impl<T, A, B> Goal<T> for Disjunction<T, A, B> where T: PartialEq + Unif<T>, A: Goal<T>, B: Goal<T> {
103    fn eval(&self, state: &State<T>) -> PossibleStates<T> {
104        let mut da = self.a.eval(state).into_iter();
105        let mut db = self.b.eval(state).into_iter();
106        let mut result: Vec<State<T>> = Vec::with_capacity(0);
107        loop {
108            let sa = da.next();
109            let sb = db.next();
110
111            let mut found = false;
112            if let Some(state) = sa { result.push(state); found = true; }
113            if let Some(state) = sb { result.push(state); found = true; }
114
115            if !found { break; }
116        }
117        result
118    }
119}
120
121/// Creates a `Disjunction` goal which returns the disjunction (logical OR) of evaluating the two sub-goals.
122pub fn disj<T, A, B>(a: A, b: B) -> Disjunction<T, A, B> where T: PartialEq + Unif<T>, A: Goal<T>, B: Goal<T> {
123    Disjunction { a: a, b: b, _m: PhantomData }
124}
125
126
127/// Evaluating a `Predicate` goal returns the given state only if the function returns `true`.
128pub struct Predicate<'a, T, F> where T: PartialEq + Unif<T>, F: Fn(&State<T>) -> bool + 'a {
129    f: &'a F,
130    _m: PhantomData<T>,
131}
132
133impl<'a, T, F> Goal<T> for Predicate<'a, T, F> where T: PartialEq + Unif<T>, F: Fn(&State<T>) -> bool {
134    fn eval(&self, state: &State<T>) -> PossibleStates<T> {
135        let f = self.f;
136        if f(state) {
137            vec![state.clone()]
138        } else {
139            Vec::with_capacity(0)
140        }
141    }
142}
143
144/// Creates a `Predicate` goal that filters a set of possible states with the given function.
145pub fn pred<'a, T, F>(f: &'a F) -> Predicate<'a, T, F> where T: PartialEq + Unif<T>, F: Fn(&State<T>) -> bool {
146    Predicate { f: f, _m: PhantomData }
147}
148
149
150macro_rules! unif_prim {
151    ( $t:ty ) => {
152        impl Unif<$t> for $t {
153            fn unify(&self, other: &$t, prev: &State<$t>) -> PossibleStates<$t> {
154                if self.eq(other) { vec![prev.clone()] } else { PossibleStates::new() }
155            }
156        }
157    }
158}
159
160unif_prim!(bool);
161unif_prim!(char);
162unif_prim!(f32);
163unif_prim!(f64);
164unif_prim!(i16);
165unif_prim!(i32);
166unif_prim!(i64);
167unif_prim!(i8);
168unif_prim!(isize);
169unif_prim!(u16);
170unif_prim!(u32);
171unif_prim!(u64);
172unif_prim!(u8);
173unif_prim!(usize);
174unif_prim!(String);
175
176
177#[cfg(test)]
178mod tests {
179    use state::{State};
180    use super::{Goal, fail, unify_val, unify_vars, conj, disj, pred};
181
182    #[test]
183    fn test_bind_val() {
184        let s = State::<i32>::empty();
185        let (v, s) = s.make_var();
186
187        let n: i32 = 34;
188        let g = unify_val(&v, n);
189
190        let results = g.eval(&s);
191        assert_eq!(results.len(), 1);
192
193        let val = results[0].get(&v).unwrap();
194        assert_eq!(val, &n);
195    }
196
197    #[test]
198    fn test_bind_var() {
199        let s = State::<i32>::empty();
200        let (a, s) = s.make_var();
201        let (b, s) = s.make_var();
202
203        let n: i32 = 12;
204        let g1 = unify_vars(&a, &b);
205        let g2 = unify_val(&b, n);
206        let g = conj(g1, g2);
207
208        let results = g.eval(&s);
209        assert_eq!(results.len(), 1);
210
211        let val = results[0].get(&a).unwrap();
212        assert_eq!(val, &n);
213    }
214
215    #[test]
216    fn test_conj_fail() {
217        let s = State::<i32>::empty();
218        let (v, s) = s.make_var();
219        let g1 = unify_val(&v, 56);
220        let g2 = fail::<i32>();
221        let g = conj(g1, g2);
222
223        let results = g.eval(&s);
224        assert_eq!(results.len(), 0);
225    }
226
227    #[test]
228    fn test_disj_fail() {
229        let s = State::<i32>::empty();
230        let (v, s) = s.make_var();
231        let g1 = fail::<i32>();
232        let g2 = unify_val(&v, 43);
233        let g = disj(g1, g2);
234
235        let results = g.eval(&s);
236        assert_eq!(results.len(), 1);
237
238        let val = results[0].get(&v).unwrap();
239        assert_eq!(val, &43);
240    }
241
242    #[test]
243    fn test_disj() {
244        let s = State::<i32>::empty();
245        let (a, s) = s.make_var();
246
247        let g1 = unify_val(&a, 123);
248        let g2 = unify_val(&a, 456);
249        let g = disj(g1, g2);
250
251        let results = g.eval(&s);
252        assert_eq!(results.len(), 2);
253
254        let val = results[0].get(&a).unwrap();
255        assert_eq!(val, &123);
256
257        let val = results[1].get(&a).unwrap();
258        assert_eq!(val, &456);
259    }
260
261    #[test]
262    fn test_pred() {
263        let s = State::<i32>::empty();
264        let (a, s) = s.make_var();
265
266        let d = disj(unify_val(&a, 123), unify_val(&a, 987));
267        let f = |s: &State<i32>| match s.get(&a) { Some(n) => *n == 987, None => false };
268        let p = pred(&f);
269        let g = conj(d, p);
270
271        let results = g.eval(&s);
272        assert_eq!(results.len(), 1);
273
274        let val = results[0].get(&a).unwrap();
275        assert_eq!(val, &987);
276    }
277}