Fixpoint interp_domain (l : seq R) (d : domain) : Prop :=
  match d with
  | Never => False
  | Always => True
  | Partial p e => p (interp l e)
  | Derivable n k f le => ex_derive_Rn k f n (nth 0 (map (interp l) le))
  | Derivable2 m n k f le =>
    let le' := map (interp l) le in
    locally_2d (fun u v => ex_derive_Rn k f m (fun i => if ssrnat.eqn i m then u else if ssrnat.eqn i n then v else nth 0 le' i)) (nth 0 le' m) (nth 0 le' n) /\
    continuity_2d_pt (fun u v => Derive_Rn k f m (fun i => if ssrnat.eqn i m then u else if ssrnat.eqn i n then v else nth 0 le' i)) (nth 0 le' m) (nth 0 le' n)
  | Continuous n f => continuity_pt (fun x => interp (set_nth R0 l n x) f) (nth R0 l n)
  | Continuous2 m n f => continuity_2d_pt (fun x y => interp (set_nth R0 (set_nth R0 l n y) m x) f) (nth R0 l m) (nth R0 l n)
  | Integrable f e1 e2 => ex_RInt (fun x => interp (x :: l) f) (interp l e1) (interp l e2)
  | ParamIntegrable n f e1 e2 =>
    locally (nth R0 l n) (fun y => ex_RInt (fun t => interp (t :: set_nth R0 l n y) f) (interp l e1) (interp l e2))
  | LocallyParamIntegrable n f e =>
    let a := interp l e in
    exists eps : posreal, locally (nth R0 l n) (fun y => ex_RInt (fun t => interp (t :: set_nth R0 l n y) f) (a - eps) (a + eps))
  | And ld => foldr (fun d acc => interp_domain l d /\ acc) True ld
  | Forall e1 e2 s =>
    let a1 := interp l e1 in let a2 := interp l e2 in
    forall t, Rmin a1 a2 <= t <= Rmax a1 a2 ->
    interp_domain (t :: l) s
  | Forone e s => interp_domain (interp l e :: l) s
  | Locally n s =>
    locally (nth R0 l n) (fun x => interp_domain (set_nth R0 l n x) s)
  | Locally2 m n s =>
    locally_2d (fun x y => interp_domain (set_nth R0 (set_nth R0 l n y) m x) s) (nth R0 l m) (nth R0 l n)
  | ForallWide n e1 e2 s =>
    let a1 := interp l e1 in let a2 := interp l e2 in
    exists d : posreal,
    forall t u, Rmin a1 a2 - d < t < Rmax a1 a2 + d -> Rabs (u - nth R0 l n) < d ->
    interp_domain (t :: set_nth R0 l n u) s
  end.Fixpoint is_const (e : expr) n : bool :=
  match e with
  | Var v => negb (ssrnat.eqn v n)
  | AppExt k f le => foldr (fun v acc => andb (is_const v n) acc) true le
  | AppExtD k f p le => false
  | App f e => andb (is_const f (S n)) (is_const e n)
  | Subst f e => andb (orb (ssrnat.eqn n 0) (is_const f n)) (is_const e n)
  | Cst _ => true
  | Binary b e1 e2 => andb (is_const e1 n) (is_const e2 n)
  | Unary u e => is_const e n
  | Int f e1 e2 => andb (is_const f (S n)) (andb (is_const e1 n) (is_const e2 n))
  end.

(* Specifications: *)
Lemma is_const_correct : forall e n, is_const e n = true -> forall l x1 x2, interp (set_nth 0 l n x1) e = interp (set_nth 0 l n x2) e.
Lemma nth_map' : forall {T1} x1 {T2} (f : T1 -> T2) n s, nth (f x1) (map f s) n = f (nth x1 s n).
Lemma interp_ext : forall l1 l2 e, (forall k, nth 0 l1 k = nth 0 l2 k) -> interp l1 e = interp l2 e.
Lemma interp_set_nth : forall n l e, interp (set_nth 0 l n (nth 0 l n)) e = interp l e.
Lemma interp_domain_ext : forall l1 l2 b, (forall k, nth 0 l1 k = nth 0 l2 k) -> interp_domain l1 b -> interp_domain l2 b.
Lemma interp_domain_set_nth : forall n l b, interp_domain (set_nth 0 l n (nth 0 l n)) b <-> interp_domain l b.