Notation canons := (list (A*B)).(*Definition isEq (c : comparison) := match c with Eq => true | _ => false end.*)

Fixpoint lookC (a: A) (cs: canons) : B :=
  match cs with nil => fAB a
  | (a1, b1)::cs' => if isEq (A_cmp a a1) then b1
                     else lookC a cs'
  end.Fixpoint rewriteC (b1 b2 : B) (cs: canons) : canons :=
  match cs with nil => nil
  | (a1, b1')::cs' =>
    let new_cs := rewriteC b1 b2 cs' in
    if isEq (B_cmp b1 b1') then (a1, b2)::new_cs else (a1, b1')::new_cs end.Definition mergeC (a1 a2 : A) (cs: canons) : canons :=
  match lookC a1 cs, lookC a2 cs with b1, b2 =>
    if isEq (B_cmp b1 b2) then cs
    else (a1, b2)::(a2, b2)::rewriteC b1 b2 cs end.(*
Module TestCClosure.
Require Import NatOrderedType. Import Nat_as_DT.

Notation lookC := (lookC _ _ eq_dec (fun n => n)).
Notation rewriteC := (@rewriteC nat nat eq_dec).
Notation mergeC := (mergeC _ _ eq_dec eq_dec (fun n => n)).

Compute mergeC 1 2 nil.
Compute mergeC 1 2 (mergeC 3 4 nil).
Compute lookC 3 (mergeC 1 2 (mergeC 3 4 (mergeC 5 6 nil))).
Compute lookC 3 (mergeC 4 5 (mergeC 3 4 (mergeC 5 6 nil))).
Compute lookC 3 (mergeC 1 8 (mergeC 3 4 (mergeC 1 3 (mergeC 1 2 nil)))).

End TestCClosure.
*)

Notation expr_get := (lookC _ _ expr_cmp (@id _)).Notation expr_merge := (mergeC _ _ expr_cmp expr_cmp (@id _)).(* used internally *)
Local Notation expr_rewriteC := (rewriteC expr _ expr_cmp).

Lemma cclose_sound l s : listd clause_denote inter TT l s -> listd clause_denote inter TT (cclose l) s.