mirror of
https://github.com/c-cube/sidekick.git
synced 2026-05-05 17:04:39 -04:00
85 lines
2.4 KiB
OCaml
85 lines
2.4 KiB
OCaml
open Types_
|
|
module T = Term
|
|
|
|
(* Pair-keyed table for def_eq cache *)
|
|
module T2_tbl = CCHashtbl.Make (struct
|
|
type t = term * term
|
|
|
|
let equal (a1, b1) (a2, b2) = T.equal a1 a2 && T.equal b1 b2
|
|
let hash (a, b) = CCHash.combine3 91 (T.hash a) (T.hash b)
|
|
end)
|
|
|
|
(** Weak head normal form. Beta-reduces at the head until stuck. Memoised via
|
|
[cache]. *)
|
|
let whnf ?(cache = T.Tbl.create 16) store e =
|
|
let rec loop e =
|
|
match T.Tbl.find_opt cache e with
|
|
| Some v -> v
|
|
| None ->
|
|
let v = step e in
|
|
T.Tbl.add cache e v;
|
|
v
|
|
and step e =
|
|
match T.view e with
|
|
| E_app (f, a) ->
|
|
let f' = loop f in
|
|
(match T.view f' with
|
|
| E_lam (_, _, body) -> loop (T.DB.subst_db0 store body ~by:a)
|
|
| _ ->
|
|
if f == f' then
|
|
e
|
|
else
|
|
T.app store f' a)
|
|
| _ -> e
|
|
in
|
|
loop e
|
|
|
|
(** Definitional equality: WHNF both sides, then compare structurally. Uses
|
|
[Level.judge_eq] for universe levels. Memoised via pair cache to handle
|
|
sharing in DAGs. *)
|
|
let def_eq store e1 e2 =
|
|
let whnf_cache = T.Tbl.create 16 in
|
|
let eq_cache : bool T2_tbl.t = T2_tbl.create 16 in
|
|
let whnf = whnf ~cache:whnf_cache store in
|
|
|
|
let rec go e1 e2 =
|
|
if T.equal e1 e2 then
|
|
true
|
|
else (
|
|
(* canonical order to halve cache size *)
|
|
let key =
|
|
if T.compare e1 e2 <= 0 then
|
|
e1, e2
|
|
else
|
|
e2, e1
|
|
in
|
|
match T2_tbl.find_opt eq_cache key with
|
|
| Some b -> b
|
|
| None ->
|
|
(* assume true while recursing (for coinductive guard on open terms) *)
|
|
T2_tbl.add eq_cache key true;
|
|
let r = check e1 e2 in
|
|
T2_tbl.replace eq_cache key r;
|
|
r
|
|
)
|
|
and check e1 e2 =
|
|
let e1 = whnf e1 in
|
|
let e2 = whnf e2 in
|
|
if T.equal e1 e2 then
|
|
true
|
|
else (
|
|
match T.view e1, T.view e2 with
|
|
| E_type l1, E_type l2 -> Level.judge_eq (T.Store.lvl_store store) l1 l2
|
|
| E_var v1, E_var v2 -> Var.equal v1 v2
|
|
| E_const c1, E_const c2 -> Const.equal c1 c2
|
|
| E_bound_var b1, E_bound_var b2 -> Bvar.equal b1 b2
|
|
| E_app (f1, a1), E_app (f2, a2) -> go f1 f2 && go a1 a2
|
|
| E_lam (_, ty1, b1), E_lam (_, ty2, b2) -> go ty1 ty2 && go b1 b2
|
|
| E_pi (_, ty1, b1), E_pi (_, ty2, b2) -> go ty1 ty2 && go b1 b2
|
|
| _ -> false
|
|
)
|
|
in
|
|
go e1 e2
|
|
|
|
(* Install into the kernel *)
|
|
let () = T.Internal_.def_eq_ref := def_eq
|