use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;
pub fn pair() -> Term {
abs(abs(abs(
Var(1)
.app(Var(3))
.app(Var(2))
)))
}
pub fn first() -> Term { abs(Var(1).app(tru())) }
pub fn second() -> Term { abs(Var(1).app(fls())) }
impl Term {
pub fn is_pair(&self) -> bool {
self.fst_ref().is_ok() && self.snd_ref().is_ok()
}
pub fn unpair(self) -> Result<(Term, Term), Error> {
if let Abs(_) = self {
if let Ok((wrapped_a, b)) = self.unabs().and_then(|t| t.unapp()) {
Ok((try!(wrapped_a.rhs()), b))
} else {
Err(NotAPair)
}
} else {
if let Ok((wrapped_a, b)) = self.unapp() {
Ok((try!(wrapped_a.rhs()), b))
} else {
Err(NotAPair)
}
}
}
pub fn unpair_ref(&self) -> Result<(&Term, &Term), Error> {
if let Abs(_) = *self {
if let Ok((wrapped_a, b)) = self.unabs_ref().and_then(|t| t.unapp_ref()) {
Ok((try!(wrapped_a.rhs_ref()), b))
} else {
Err(NotAPair)
}
} else {
if let Ok((wrapped_a, b)) = self.unapp_ref() {
Ok((try!(wrapped_a.rhs_ref()), b))
} else {
Err(NotAPair)
}
}
}
pub fn unpair_ref_mut(&mut self) -> Result<(&mut Term, &mut Term), Error> {
if let Abs(_) = *self {
if let Ok((wrapped_a, b)) = self.unabs_ref_mut().and_then(|t| t.unapp_ref_mut()) {
Ok((try!(wrapped_a.rhs_ref_mut()), b))
} else {
Err(NotAPair)
}
} else {
if let Ok((wrapped_a, b)) = self.unapp_ref_mut() {
Ok((try!(wrapped_a.rhs_ref_mut()), b))
} else {
Err(NotAPair)
}
}
}
pub fn fst(self) -> Result<Term, Error> {
Ok(try!(self.unpair()).0)
}
pub fn fst_ref(&self) -> Result<&Term, Error> {
Ok(try!(self.unpair_ref()).0)
}
pub fn fst_ref_mut(&mut self) -> Result<&mut Term, Error> {
Ok(try!(self.unpair_ref_mut()).0)
}
pub fn snd(self) -> Result<Term, Error> {
Ok(try!(self.unpair()).1)
}
pub fn snd_ref(&self) -> Result<&Term, Error> {
Ok(try!(self.unpair_ref()).1)
}
pub fn snd_ref_mut(&mut self) -> Result<&mut Term, Error> {
Ok(try!(self.unpair_ref_mut()).1)
}
}
impl From<(Term, Term)> for Term {
fn from((t1, t2): (Term, Term)) -> Self {
abs(
Var(1)
.app(t1)
.app(t2)
)
}
}
#[cfg(test)]
mod test {
use super::*;
use reduction::beta_full;
#[test]
fn pair_from_pair() {
assert_eq!(Term::from((0.into(), 1.into())), beta_full(pair().app(0.into()).app(1.into())));
}
#[test]
fn pair_operations() {
let pair_four_three = beta_full(pair().app(4.into()).app(3.into()));
assert!(pair_four_three.is_pair());
assert_eq!(pair_four_three.fst_ref(), Ok(&4.into()));
assert_eq!(pair_four_three.snd_ref(), Ok(&3.into()));
let unpaired = pair_four_three.unpair();
assert_eq!(unpaired, Ok((4.into(), 3.into())));
}
}