use term::*;
use term::Error::*;
use booleans::*;
pub fn pair() -> Term {
abs(abs(abs(
app!(Var(1), Var(3), Var(2))
)))
}
pub fn fst() -> Term { abs(Var(1).app(tru())) }
pub fn snd() -> Term { abs(Var(1).app(fls())) }
impl Term {
pub fn is_pair(&self) -> bool {
self.unpair_ref().is_ok()
}
pub fn unpair(self) -> Result<(Term, Term), Error> {
let candidate = if let Abs(abstracted) = self { *abstracted } else { self };
if let Ok((wrapped_a, b)) = candidate.unapp() {
Ok((try!(wrapped_a.rhs()), b))
} else {
Err(NotAPair)
}
}
pub fn unpair_ref(&self) -> Result<(&Term, &Term), Error> {
let candidate = if let Abs(ref abstracted) = *self { abstracted } else { self };
if let Ok((wrapped_a, b)) = candidate.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> {
let mut candidate = if let Abs(ref mut abstracted) = *self { abstracted } else { self };
if let Ok((wrapped_a, b)) = candidate.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(app!(Var(1), t1, t2))
}
}
#[cfg(test)]
mod tests {
use super::*;
use reduction::beta;
use reduction::Order::*;
#[test]
fn pair_from_pair() {
assert_eq!(Term::from((0.into(), 1.into())),
beta(app!(pair(), 0.into(), 1.into()), NOR, 0, false));
}
#[test]
fn pair_operations() {
let pair_four_three = beta(app!(pair(), 4.into(), 3.into()), NOR, 0, false);
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())));
}
}