summaryrefslogtreecommitdiff
path: root/dhall/src/semantics/core/value.rs
diff options
context:
space:
mode:
Diffstat (limited to 'dhall/src/semantics/core/value.rs')
-rw-r--r--dhall/src/semantics/core/value.rs118
1 files changed, 10 insertions, 108 deletions
diff --git a/dhall/src/semantics/core/value.rs b/dhall/src/semantics/core/value.rs
index 35913cf..42da653 100644
--- a/dhall/src/semantics/core/value.rs
+++ b/dhall/src/semantics/core/value.rs
@@ -303,7 +303,9 @@ impl Value {
} => TyExprKind::Expr(ExprKind::Lam(
binder.to_label(),
annot.to_tyexpr(qenv),
- closure.normalize().to_tyexpr(qenv.insert()),
+ closure
+ .apply_var(NzVar::new(qenv.size()))
+ .to_tyexpr(qenv.insert()),
)),
ValueKind::PiClosure {
binder,
@@ -312,7 +314,9 @@ impl Value {
} => TyExprKind::Expr(ExprKind::Pi(
binder.to_label(),
annot.to_tyexpr(qenv),
- closure.normalize().to_tyexpr(qenv.insert()),
+ closure
+ .apply_var(NzVar::new(qenv.size()))
+ .to_tyexpr(qenv.insert()),
)),
ValueKind::AppliedBuiltin(b, args, types) => {
TyExprKind::Expr(args.into_iter().zip(types.into_iter()).fold(
@@ -692,120 +696,17 @@ impl Closure {
pub fn apply(&self, val: Value) -> Value {
self.body.normalize_whnf(&self.env.insert_value(val))
}
- pub fn apply_fresh(&self, env: QuoteEnv) -> Value {
+ pub fn apply_var(&self, var: NzVar) -> Value {
let val = Value::from_kind_and_type(
- ValueKind::Var(AlphaVar::default(), NzVar::new(env.size())),
+ ValueKind::Var(AlphaVar::default(), var),
self.arg_ty.clone(),
);
self.apply(val)
}
- pub fn normalize(&self) -> Value {
- self.body
- .normalize_whnf(&self.env.insert_type(self.arg_ty.clone()))
- }
}
/// Compare two values for equality modulo alpha/beta-equivalence.
// TODO: use Rc comparison to shortcut on identical pointers
-fn equiv(val1: &Value, val2: &Value) -> bool {
- struct ValueWithEnv<'v> {
- val: &'v Value,
- env: QuoteEnv,
- }
- impl<'v> PartialEq for ValueWithEnv<'v> {
- fn eq(&self, other: &ValueWithEnv<'v>) -> bool {
- equiv_with_env(self.env, self.val, other.env, other.val)
- }
- }
- // Push the given context into every subnode of the ValueKind. That way, normal equality of the
- // resulting value will take into account the context.
- fn push_context<'v>(
- env: QuoteEnv,
- kind: &'v ValueKind<Value>,
- ) -> ValueKind<ValueWithEnv<'v>> {
- kind.map_ref_with_special_handling_of_binders(
- |val| ValueWithEnv { val, env },
- |_, _, val| ValueWithEnv {
- val,
- env: env.insert(),
- },
- )
- }
-
- fn equiv_with_env<'v>(
- env1: QuoteEnv,
- val1: &'v Value,
- env2: QuoteEnv,
- val2: &'v Value,
- ) -> bool {
- use ValueKind::Var;
- let kind1 = val1.as_whnf();
- let kind2 = val2.as_whnf();
- match (&*kind1, &*kind2) {
- (Var(_, v1), Var(_, v2)) => {
- v1 == v2
- // match (env1.lookup(v1), env2.lookup(v2)) {
- // // Both vars were found in the environment, check they point to the same
- // // binder.
- // // Does that even make any sense with an incomplete environment ?
- // // I have no clue what I'm doing anymore.
- // (Some(i), Some(j)) => i == j,
- // // Both vars point to outside the environment ????
- // // (None, None) => v1 == v2,
- // _ => false,
- // }
- }
- // (Var(_, v1), Var(_, v2)) => env1.lookup(v1) == env2.lookup(v2),
- (
- ValueKind::LamClosure {
- annot: a1,
- closure: cl1,
- ..
- },
- ValueKind::LamClosure {
- annot: a2,
- closure: cl2,
- ..
- },
- ) => {
- equiv_with_env(env1, a1, env2, a2)
- && equiv_with_env(
- env1.insert(),
- &cl1.apply_fresh(env1),
- env2.insert(),
- &cl2.apply_fresh(env2),
- )
- }
- (
- ValueKind::PiClosure {
- annot: a1,
- closure: cl1,
- ..
- },
- ValueKind::PiClosure {
- annot: a2,
- closure: cl2,
- ..
- },
- ) => {
- equiv_with_env(env1, a1, env2, a2)
- && equiv_with_env(
- env1.insert(),
- &cl1.apply_fresh(env1),
- env2.insert(),
- &cl2.apply_fresh(env2),
- )
- }
- (k1, k2) => push_context(env1, k1) == push_context(env2, k2),
- }
- }
-
- // TODO: need to use ambiant env instead of creating new one
- // Might be possible to generate free variables differently to avoid this
- equiv_with_env(QuoteEnv::new(), val1, QuoteEnv::new(), val2)
-}
-
-// TODO: use Rc comparison to shortcut on identical pointers
impl std::cmp::PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
*self.as_whnf() == *other.as_whnf()
@@ -815,7 +716,8 @@ impl std::cmp::Eq for Value {}
impl std::cmp::PartialEq for Closure {
fn eq(&self, other: &Self) -> bool {
- self.normalize() == other.normalize()
+ let v = NzVar::fresh();
+ self.apply_var(v) == other.apply_var(v)
}
}
impl std::cmp::Eq for Closure {}