use super::{Value, Hole, Unification}; use crate::time::*; use crate::item::*; use crate::character::*; use enum_map::Enum; use strum::EnumDiscriminants; pub trait Concretizable { type Concrete; fn concretize(&self) -> Option; } impl Concretizable for Hole { type Concrete = A; fn concretize(&self) -> Option { match self { Self::Val(x) => Some(x.clone()), _ => None, } } } impl< A: Clone, B: Clone, > Concretizable for (Hole, Hole) { type Concrete = (A, B); fn concretize(&self) -> Option { let a = self.0.concretize()?; let b = self.1.concretize()?; Some((a, b)) } } impl< A: Clone, B: Clone, C: Clone, > Concretizable for (Hole, Hole, Hole) { type Concrete = (A, B, C); fn concretize(&self) -> Option { let a = self.0.concretize()?; let b = self.1.concretize()?; let c = self.2.concretize()?; Some((a, b, c)) } } impl< A: Clone, B: Clone, C: Clone, D: Clone, > Concretizable for (Hole, Hole, Hole, Hole) { type Concrete = (A, B, C, D); fn concretize(&self) -> Option { let a = self.0.concretize()?; let b = self.1.concretize()?; let c = self.2.concretize()?; let d = self.3.concretize()?; Some((a, b, c, d)) } } impl< A: Clone, B: Clone, C: Clone, D: Clone, E: Clone, > Concretizable for (Hole, Hole, Hole, Hole, Hole) { type Concrete = (A, B, C, D, E); fn concretize(&self) -> Option { let a = self.0.concretize()?; let b = self.1.concretize()?; let c = self.2.concretize()?; let d = self.3.concretize()?; let e = self.4.concretize()?; Some((a, b, c, d, e)) } } pub trait Substitutable { fn substitute(&self, u: &Unification) -> Self; } impl> Substitutable for Hole { fn substitute(&self, u: &Unification) -> Self { match self { x@Self::Var(v) => if let Some(y) = u.lookup(v) && let Ok(z) = A::try_from(y) { Hole::Val(z) } else { x.clone() } x => x.clone(), } } } impl< A: Clone + TryFrom, B: Clone + TryFrom > Substitutable for (Hole, Hole) { fn substitute(&self, u: &Unification) -> Self { let (a, b) = self; (a.substitute(u), b.substitute(u)) } } impl< A: Clone + TryFrom, B: Clone + TryFrom, C: Clone + TryFrom, > Substitutable for (Hole, Hole, Hole) { fn substitute(&self, u: &Unification) -> Self { let (a, b, c) = self; (a.substitute(u), b.substitute(u), c.substitute(u)) } } impl< A: Clone + TryFrom, B: Clone + TryFrom, C: Clone + TryFrom, D: Clone + TryFrom, > Substitutable for (Hole, Hole, Hole, Hole) { fn substitute(&self, u: &Unification) -> Self { let (a, b, c, d) = self; (a.substitute(u), b.substitute(u), c.substitute(u), d.substitute(u)) } } impl< A: Clone + TryFrom, B: Clone + TryFrom, C: Clone + TryFrom, D: Clone + TryFrom, E: Clone + TryFrom, > Substitutable for (Hole, Hole, Hole, Hole, Hole) { fn substitute(&self, u: &Unification) -> Self { let (a, b, c, d, e) = self; (a.substitute(u), b.substitute(u), c.substitute(u), d.substitute(u), e.substitute(u)) } } pub trait Unifiable { fn unify(&self, other: &Self, u: Unification) -> Option; } impl Unifiable for Hole where Value: From, A: Copy, { fn unify(&self, other: &Self, mut u: Unification) -> Option { if u.unify_hole(self, other) { Some(u) } else { None } } } impl Unifiable for (Hole, Hole) where Value: From, A: Copy, Value: From, B: Copy, { fn unify(&self, other: &Self, mut u: Unification) -> Option { let (a1, b1) = self; let (a2, b2) = other; if u.unify_hole(a1, a2) && u.unify_hole(b1, b2) { Some(u) } else { None } } } impl Unifiable for (Hole, Hole, Hole) where Value: From, A: Copy, Value: From, B: Copy, Value: From, C: Copy, { fn unify(&self, other: &Self, mut u: Unification) -> Option { let (a1, b1, c1) = self; let (a2, b2, c2) = other; if u.unify_hole(a1, a2) && u.unify_hole(b1, b2) && u.unify_hole(c1, c2) { Some(u) } else { None } } } impl Unifiable for (Hole, Hole, Hole, Hole) where Value: From, A: Copy, Value: From, B: Copy, Value: From, C: Copy, Value: From, D: Copy, { fn unify(&self, other: &Self, mut u: Unification) -> Option { let (a1, b1, c1, d1) = self; let (a2, b2, c2, d2) = other; if u.unify_hole(a1, a2) && u.unify_hole(b1, b2) && u.unify_hole(c1, c2) && u.unify_hole(d1, d2) { Some(u) } else { None } } } impl Unifiable for (Hole, Hole, Hole, Hole, Hole) where Value: From, A: Copy, Value: From, B: Copy, Value: From, C: Copy, Value: From, D: Copy, Value: From, E: Copy, { fn unify(&self, other: &Self, mut u: Unification) -> Option { let (a1, b1, c1, d1, e1) = self; let (a2, b2, c2, d2, e2) = other; if u.unify_hole(a1, a2) && u.unify_hole(b1, b2) && u.unify_hole(c1, c2) && u.unify_hole(d1, d2) && u.unify_hole(e1, e2) { Some(u) } else { None } } } #[derive(Debug, Clone, PartialEq, Eq, Hash, EnumDiscriminants)] #[strum_discriminants(derive(Enum))] pub enum Relation { HasItem((Hole, Hole)), UsedItemAt((Hole, Hole, Hole