use crate::{env::{Env, IndDesc}, term::Term};
use super::ids::*;
pub fn nat() -> Term { Term::Ind(NAT_ID, vec![]) }
pub fn nat_zero() -> Term { Term::Ctor(NAT_ID, NAT_ZERO, vec![]) }
pub fn nat_next(n: Term) -> Term { Term::Ctor(NAT_ID, NAT_NEXT, vec![n]) }
pub fn nat_lit(n: u64) -> Term {
let mut t = nat_zero();
for _ in 0..n { t = nat_next(t); }
t
}
pub fn declare_nat(env: &mut Env) {
let n = nat();
env.insert(NAT_ID, IndDesc {
arity: 0,
sort: 1,
param_tel: Term::Sort(0),
constructors: vec![
n.clone(),
Term::Pi(Box::new(n.clone()), Box::new(n.clone())),
],
});
}
pub fn nat_add(n: Term, m: Term) -> Term {
Term::Elim(
NAT_ID,
Box::new(Term::Lam(Box::new(nat()), Box::new(nat()))),
vec![
m,
Term::Lam(Box::new(nat()), Box::new(Term::Lam(
Box::new(nat()),
Box::new(nat_next(Term::Var(0))),
))),
],
Box::new(n),
)
}
pub fn nat_mul(n: Term, m: Term) -> Term {
let m_shifted = crate::subst::shift(&m, 2);
Term::Elim(
NAT_ID,
Box::new(Term::Lam(Box::new(nat()), Box::new(nat()))),
vec![
nat_zero(),
Term::Lam(Box::new(nat()), Box::new(Term::Lam(
Box::new(nat()),
Box::new(nat_add(m_shifted, Term::Var(0))),
))),
],
Box::new(n),
)
}
pub fn nat_le(n: Term, m: Term) -> Term {
use super::bool::{bool_ty, bool_false, bool_true};
Term::Elim(
NAT_ID,
Box::new(Term::Lam(Box::new(nat()), Box::new(bool_ty()))),
vec![
Term::Lam(Box::new(nat()), Box::new(bool_true())),
Term::Lam(Box::new(nat()), Box::new(Term::Lam(
Box::new(Term::Pi(Box::new(nat()), Box::new(bool_ty()))),
Box::new(Term::Elim(
NAT_ID,
Box::new(Term::Lam(Box::new(nat()), Box::new(bool_ty()))),
vec![
bool_false(),
Term::Lam(Box::new(nat()), Box::new(Term::Lam(
Box::new(bool_ty()),
Box::new(Term::App(Box::new(Term::Var(3)), Box::new(Term::Var(1)))),
))),
],
Box::new(m.clone()),
)),
))),
],
Box::new(n),
)
}
pub fn nat_sub(n: Term, m: Term) -> Term {
let pred_of_ih = Term::Elim(
NAT_ID,
Box::new(Term::Lam(Box::new(nat()), Box::new(nat()))),
vec![
nat_zero(),
Term::Lam(Box::new(nat()), Box::new(Term::Lam(
Box::new(nat()),
Box::new(Term::Var(1)), ))),
],
Box::new(Term::Var(0)), );
Term::Elim(
NAT_ID,
Box::new(Term::Lam(Box::new(nat()), Box::new(nat()))),
vec![
n,
Term::Lam(Box::new(nat()), Box::new(Term::Lam(
Box::new(nat()), Box::new(pred_of_ih),
))),
],
Box::new(m),
)
}
pub fn nat_min_term() -> Term {
let outer_motive = Term::Lam(
Box::new(nat()),
Box::new(Term::Pi(Box::new(nat()), Box::new(nat()))),
);
let case_zero = Term::Lam(Box::new(nat()), Box::new(nat_zero()));
let inner_case_succ = Term::Lam(
Box::new(nat()), Box::new(Term::Lam(
Box::new(nat()), Box::new(nat_next(Term::App(
Box::new(Term::Var(3)), Box::new(Term::Var(1)), ))),
)),
);
let case_succ_body = Term::Elim(
NAT_ID,
Box::new(Term::Lam(Box::new(nat()), Box::new(nat()))),
vec![nat_zero(), inner_case_succ],
Box::new(Term::Var(0)), );
let case_succ = Term::Lam(
Box::new(nat()), Box::new(Term::Lam(
Box::new(Term::Pi(Box::new(nat()), Box::new(nat()))), Box::new(Term::Lam(
Box::new(nat()), Box::new(case_succ_body),
)),
)),
);
Term::Lam(
Box::new(nat()), Box::new(Term::Elim(
NAT_ID,
Box::new(outer_motive),
vec![case_zero, case_succ],
Box::new(Term::Var(0)), )),
)
}
pub fn nat_max_term() -> Term {
let outer_motive = Term::Lam(
Box::new(nat()),
Box::new(Term::Pi(Box::new(nat()), Box::new(nat()))),
);
let case_zero = Term::Lam(Box::new(nat()), Box::new(Term::Var(0)));
let inner_case_zero_max = nat_next(Term::Var(2)); let inner_case_succ_max = Term::Lam(
Box::new(nat()), Box::new(Term::Lam(
Box::new(nat()), Box::new(nat_next(Term::App(
Box::new(Term::Var(3)), Box::new(Term::Var(1)), ))),
)),
);
let case_succ_body = Term::Elim(
NAT_ID,
Box::new(Term::Lam(Box::new(nat()), Box::new(nat()))),
vec![inner_case_zero_max, inner_case_succ_max],
Box::new(Term::Var(0)), );
let case_succ = Term::Lam(
Box::new(nat()), Box::new(Term::Lam(
Box::new(Term::Pi(Box::new(nat()), Box::new(nat()))), Box::new(Term::Lam(
Box::new(nat()), Box::new(case_succ_body),
)),
)),
);
Term::Lam(
Box::new(nat()), Box::new(Term::Elim(
NAT_ID,
Box::new(outer_motive),
vec![case_zero, case_succ],
Box::new(Term::Var(0)), )),
)
}