1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use crate::goals::Goal;
use crate::state::constraints::{Constraint, OneOfTwo, ResolveFn, VarWatch};
use crate::DomainType;
use crate::State;
use crate::UnifyIn;
use crate::{IntoVal, Val};
use std::fmt;
use std::fmt::Debug;
use std::rc::Rc;
pub fn map_1<'a, A, AV, B, BV, D, AtoB, BtoA>(
a: AV,
b: BV,
a_to_b: AtoB,
b_to_a: BtoA,
) -> Goal<'a, D>
where
A: UnifyIn<'a, D> + Debug + 'a,
B: UnifyIn<'a, D> + Debug + 'a,
AV: IntoVal<A>,
BV: IntoVal<B>,
D: DomainType<'a, A> + DomainType<'a, B>,
AtoB: Fn(&A) -> B + 'a,
BtoA: Fn(&B) -> A + 'a,
{
Goal::constraint(Map1 {
a: a.into_val(),
b: b.into_val(),
a_to_b: Rc::new(a_to_b),
b_to_a: Rc::new(b_to_a),
})
}
pub struct Map1<'a, A: Debug, B: Debug> {
a: Val<A>,
b: Val<B>,
a_to_b: Rc<dyn Fn(&A) -> B + 'a>,
b_to_a: Rc<dyn Fn(&B) -> A + 'a>,
}
impl<'a, A: Debug, B: Debug> Debug for Map1<'a, A, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Map1 {:?} {:?}", self.a, self.b)
}
}
impl<'a, A, B, Dom> Constraint<'a, Dom> for Map1<'a, A, B>
where
A: UnifyIn<'a, Dom> + Debug + 'a,
B: UnifyIn<'a, Dom> + Debug + 'a,
Dom: DomainType<'a, A> + DomainType<'a, B> + 'a,
{
fn attempt(&self, state: &State<'a, Dom>) -> Result<ResolveFn<'a, Dom>, VarWatch> {
let resolved = OneOfTwo::resolve(&self.a, &self.b, state)?;
match resolved {
OneOfTwo::A(a, b) => {
let f = self.a_to_b.clone();
Ok(Box::new(move |state| state.unify(&f(&*a).into_val(), &b)))
}
OneOfTwo::B(a, b) => {
let f = self.b_to_a.clone();
Ok(Box::new(move |state| state.unify(&f(&*b).into_val(), &a)))
}
}
}
}
#[cfg(test)]
mod tests {
use super::map_1;
use crate::example::I32;
use crate::goals::unify::unify;
use crate::goals::Goal;
use crate::util;
use crate::value::var;
#[test]
fn succeeds() {
let x = var();
let y = var();
let goals: Vec<Goal<I32>> =
vec![unify(1, x), unify(2, y), map_1(x, y, |x| x + 1, |y| y - 1)];
util::assert_permutations_resolve_to(goals, (x, y), vec![(1, 2)]);
}
}