use crate::declaration::{ConstantInfo, ConstantVal, QuotKind, QuotVal};
use crate::env::EnvError;
use crate::Node;
use crate::{BinderInfo, Environment, Expr, Level, Name};
use std::rc::Rc;
fn name_quot() -> Name {
Name::str("Quot")
}
fn name_quot_mk() -> Name {
Name::str("Quot").append_str("mk")
}
fn name_quot_lift() -> Name {
Name::str("Quot").append_str("lift")
}
fn name_quot_ind() -> Name {
Name::str("Quot").append_str("ind")
}
fn name_eq() -> Name {
Name::str("Eq")
}
fn prop() -> Expr {
Expr::Sort(Level::zero())
}
fn sort_param(u: &str) -> Expr {
Expr::Sort(Level::param(Name::str(u)))
}
fn arrow(dom: Expr, cod: Expr) -> Expr {
Expr::Pi(
BinderInfo::Default,
Name::str("_"),
Node::new(dom),
Node::new(cod),
)
}
fn rel_type(alpha_idx: u32) -> Expr {
let body = prop();
let inner = Expr::Pi(
BinderInfo::Default,
Name::str("b"),
Node::new(Expr::BVar(alpha_idx + 1)),
Node::new(body),
);
Expr::Pi(
BinderInfo::Default,
Name::str("a"),
Node::new(Expr::BVar(alpha_idx)),
Node::new(inner),
)
}
fn quot_type() -> Expr {
let body = sort_param("u");
let r_pi = Expr::Pi(
BinderInfo::Default,
Name::str("r"),
Node::new(rel_type(0)),
Node::new(body),
);
Expr::Pi(
BinderInfo::Implicit,
Name::str("α"),
Node::new(sort_param("u")),
Node::new(r_pi),
)
}
fn quot_app(alpha_idx: u32, r_idx: u32) -> Expr {
Expr::App(
Node::new(Expr::App(
Node::new(Expr::Const(name_quot(), vec![Level::param(Name::str("u"))])),
Node::new(Expr::BVar(alpha_idx)),
)),
Node::new(Expr::BVar(r_idx)),
)
}
fn quot_mk_type() -> Expr {
let result = quot_app(2, 1);
let elem_pi = Expr::Pi(
BinderInfo::Default,
Name::str("a"),
Node::new(Expr::BVar(1)),
Node::new(result),
);
let r_pi = Expr::Pi(
BinderInfo::Default,
Name::str("r"),
Node::new(rel_type(0)),
Node::new(elem_pi),
);
Expr::Pi(
BinderInfo::Implicit,
Name::str("α"),
Node::new(sort_param("u")),
Node::new(r_pi),
)
}
fn eq_app(lvl: Level, ty: Expr, lhs: Expr, rhs: Expr) -> Expr {
Expr::App(
Node::new(Expr::App(
Node::new(Expr::App(
Node::new(Expr::Const(name_eq(), vec![lvl])),
Node::new(ty),
)),
Node::new(lhs),
)),
Node::new(rhs),
)
}
fn quot_lift_type() -> Expr {
let lvl_v = Level::param(Name::str("v"));
let result = Expr::BVar(3);
let q_dom = quot_app(4, 3);
let q_pi = Expr::Pi(
BinderInfo::Default,
Name::str("q"),
Node::new(q_dom),
Node::new(result),
);
let r_a_b = Expr::App(
Node::new(Expr::App(
Node::new(Expr::BVar(4)), Node::new(Expr::BVar(1)), )),
Node::new(Expr::BVar(0)), );
let eq_fa_fb = {
let f_a = Expr::App(Node::new(Expr::BVar(3)), Node::new(Expr::BVar(2)));
let f_b = Expr::App(Node::new(Expr::BVar(3)), Node::new(Expr::BVar(1)));
eq_app(lvl_v.clone(), Expr::BVar(4), f_a, f_b)
};
let impl_arrow = arrow(r_a_b, eq_fa_fb);
let b_pi = Expr::Pi(
BinderInfo::Default,
Name::str("b"),
Node::new(Expr::BVar(4)),
Node::new(impl_arrow),
);
let a_pi = Expr::Pi(
BinderInfo::Default,
Name::str("a"),
Node::new(Expr::BVar(3)),
Node::new(b_pi),
);
let h_pi = Expr::Pi(
BinderInfo::Default,
Name::str("h"),
Node::new(a_pi),
Node::new(q_pi),
);
let f_dom = Expr::Pi(
BinderInfo::Default,
Name::str("_"),
Node::new(Expr::BVar(2)), Node::new(Expr::BVar(1)), );
let f_pi = Expr::Pi(
BinderInfo::Default,
Name::str("f"),
Node::new(f_dom),
Node::new(h_pi),
);
let beta_pi = Expr::Pi(
BinderInfo::Implicit,
Name::str("β"),
Node::new(Expr::Sort(lvl_v)),
Node::new(f_pi),
);
let r_pi = Expr::Pi(
BinderInfo::Implicit,
Name::str("r"),
Node::new(rel_type(0)),
Node::new(beta_pi),
);
Expr::Pi(
BinderInfo::Implicit,
Name::str("α"),
Node::new(sort_param("u")),
Node::new(r_pi),
)
}
fn quot_ind_type() -> Expr {
let result = Expr::App(Node::new(Expr::BVar(2)), Node::new(Expr::BVar(0)));
let q_dom = quot_app(3, 2);
let q_pi = Expr::Pi(
BinderInfo::Default,
Name::str("q"),
Node::new(q_dom),
Node::new(result),
);
let mk_app = Expr::App(
Node::new(Expr::App(
Node::new(Expr::App(
Node::new(Expr::Const(
name_quot_mk(),
vec![Level::param(Name::str("u"))],
)),
Node::new(Expr::BVar(3)), )),
Node::new(Expr::BVar(2)), )),
Node::new(Expr::BVar(0)), );
let beta_mk = Expr::App(Node::new(Expr::BVar(1)), Node::new(mk_app));
let a_pi = Expr::Pi(
BinderInfo::Default,
Name::str("a"),
Node::new(Expr::BVar(2)),
Node::new(beta_mk),
);
let m_pi = Expr::Pi(
BinderInfo::Default,
Name::str("m"),
Node::new(a_pi),
Node::new(q_pi),
);
let beta_dom = Expr::Pi(
BinderInfo::Default,
Name::str("_"),
Node::new(quot_app(1, 0)),
Node::new(prop()),
);
let beta_pi = Expr::Pi(
BinderInfo::Implicit,
Name::str("β"),
Node::new(beta_dom),
Node::new(m_pi),
);
let r_pi = Expr::Pi(
BinderInfo::Implicit,
Name::str("r"),
Node::new(rel_type(0)),
Node::new(beta_pi),
);
Expr::Pi(
BinderInfo::Implicit,
Name::str("α"),
Node::new(sort_param("u")),
Node::new(r_pi),
)
}
pub fn canonical_quot_type(kind: QuotKind) -> Expr {
match kind {
QuotKind::Type => quot_type(),
QuotKind::Mk => quot_mk_type(),
QuotKind::Lift => quot_lift_type(),
QuotKind::Ind => quot_ind_type(),
}
}
pub fn canonical_quot_level_params(kind: QuotKind) -> Vec<Name> {
match kind {
QuotKind::Type | QuotKind::Mk | QuotKind::Ind => vec![Name::str("u")],
QuotKind::Lift => vec![Name::str("u"), Name::str("v")],
}
}
pub fn quot_sound_name() -> Name {
Name::str("Quot").append_str("sound")
}
pub fn canonical_quot_sound_type() -> Expr {
let lvl_u = Level::param(Name::str("u"));
let quot_alpha_r = quot_app(4, 3);
let mk = |x: u32| {
Expr::App(
Node::new(Expr::App(
Node::new(Expr::App(
Node::new(Expr::Const(name_quot_mk(), vec![lvl_u.clone()])),
Node::new(Expr::BVar(4)), )),
Node::new(Expr::BVar(3)), )),
Node::new(Expr::BVar(x)),
)
};
let (mk_a, mk_b) = (mk(2), mk(1));
let body = eq_app(lvl_u, quot_alpha_r, mk_a, mk_b);
let r_a_b = Expr::App(
Node::new(Expr::App(
Node::new(Expr::BVar(2)), Node::new(Expr::BVar(1)), )),
Node::new(Expr::BVar(0)), );
let hyp_arrow = Expr::Pi(
BinderInfo::Default,
Name::str("_"),
Node::new(r_a_b),
Node::new(body),
);
let b_pi = Expr::Pi(
BinderInfo::Implicit,
Name::str("b"),
Node::new(Expr::BVar(2)),
Node::new(hyp_arrow),
);
let a_pi = Expr::Pi(
BinderInfo::Implicit,
Name::str("a"),
Node::new(Expr::BVar(1)),
Node::new(b_pi),
);
let r_pi = Expr::Pi(
BinderInfo::Implicit,
Name::str("r"),
Node::new(rel_type(0)),
Node::new(a_pi),
);
Expr::Pi(
BinderInfo::Implicit,
Name::str("α"),
Node::new(sort_param("u")),
Node::new(r_pi),
)
}
pub fn canonical_quot_sound_level_params() -> Vec<Name> {
vec![Name::str("u")]
}
fn canonical_quot_val(name: Name, kind: QuotKind) -> QuotVal {
QuotVal {
common: ConstantVal {
name,
level_params: canonical_quot_level_params(kind),
ty: canonical_quot_type(kind),
},
kind,
}
}
fn check_eq_present(env: &Environment) -> Result<(), EnvError> {
let eq_name = name_eq();
let iv = env.get_inductive_val(&eq_name).ok_or_else(|| {
EnvError::InvalidQuotient("`Eq` must be declared before quotients".into())
})?;
if iv.ctors.len() != 1 {
return Err(EnvError::InvalidQuotient(
"`Eq` must be an inductive with exactly one constructor".into(),
));
}
if !iv.is_prop {
return Err(EnvError::InvalidQuotient(
"`Eq` must be a `Prop`-valued inductive".into(),
));
}
let ctor_name = &iv.ctors[0];
let cv = env
.get_constructor_val(ctor_name)
.ok_or_else(|| EnvError::InvalidQuotient("`Eq`'s constructor must be registered".into()))?;
if cv.induct != eq_name {
return Err(EnvError::InvalidQuotient(
"`Eq`'s constructor does not point back to `Eq`".into(),
));
}
Ok(())
}
impl Environment {
pub fn add_quot(&mut self) -> Result<(), EnvError> {
if self.quot_initialized() {
return Err(EnvError::InvalidQuotient(
"quotients have already been initialized".into(),
));
}
check_eq_present(self)?;
let decls = [
(name_quot(), QuotKind::Type),
(name_quot_mk(), QuotKind::Mk),
(name_quot_lift(), QuotKind::Lift),
(name_quot_ind(), QuotKind::Ind),
];
for (name, _) in &decls {
if self.contains(name) {
return Err(EnvError::DuplicateDeclaration(name.clone()));
}
}
for (name, kind) in decls {
let qv = canonical_quot_val(name, kind);
self.insert_quotient(ConstantInfo::Quotient(qv));
}
self.set_quot_initialized();
Ok(())
}
}