use logicaffeine_kernel::prelude::StandardLibrary;
use logicaffeine_kernel::{defeq_for_test, unify, Context, MetaCtx, Term};
fn g(n: &str) -> Term {
Term::Global(n.to_string())
}
fn v(n: &str) -> Term {
Term::Var(n.to_string())
}
fn app(f: Term, x: Term) -> Term {
Term::App(Box::new(f), Box::new(x))
}
fn lam(p: &str, t: Term, b: Term) -> Term {
Term::Lambda { param: p.to_string(), param_type: Box::new(t), body: Box::new(b) }
}
fn std_ctx() -> Context {
let mut ctx = Context::new();
StandardLibrary::register(&mut ctx);
ctx
}
#[test]
fn function_unifies_with_its_eta_expansion() {
let ctx = std_ctx();
let mut mctx = MetaCtx::new();
let eta = lam("x", g("Nat"), app(g("Succ"), v("x")));
assert!(unify(&ctx, &mut mctx, &eta, &g("Succ")), "λx. Succ x must unify with Succ (η)");
let mut mctx2 = MetaCtx::new();
assert!(unify(&ctx, &mut mctx2, &g("Succ"), &eta), "Succ must unify with λx. Succ x (η)");
}
#[test]
fn eta_solves_a_metavariable_under_a_binder() {
let ctx = std_ctx();
let mut mctx = MetaCtx::new();
let m = mctx.fresh();
let lhs = lam("x", g("Nat"), app(m.clone(), v("x")));
assert!(unify(&ctx, &mut mctx, &lhs, &g("Succ")), "η + pattern must solve ?M");
if let Term::Var(name) = &m {
let sol = mctx.solution(name).expect("?M is solved");
assert!(defeq_for_test(&ctx, sol, &g("Succ")), "?M ≡ Succ (got {sol})");
} else {
panic!("fresh metavariable should be a Var");
}
}
#[test]
fn distinct_functions_do_not_unify_via_eta() {
let ctx = std_ctx();
let mut mctx = MetaCtx::new();
let eta = lam("x", g("Nat"), app(g("Succ"), v("x")));
assert!(!unify(&ctx, &mut mctx, &eta, &g("Zero")), "η must not unify Succ with Zero");
}