Theory Big_Step_Value

theory Big_Step_Value
imports
  Big_Step_Sterm
  "../Terms/Value"
begin

subsection ‹Big-step semantics evaluating to @{typ value}›

primrec vrule :: "vrule ⇒ bool" where
"vrule (_, rhs) ⟷ vwellformed rhs ∧ vclosed rhs ∧ ¬ is_Vconstr rhs"

locale vrules = constants C_info "fst |`| fset_of_list rs" for C_info and rs :: "vrule list" +
  assumes all_rules: "list_all vrule rs"
  assumes distinct: "distinct (map fst rs)"
  assumes not_shadows: "list_all (λ(_, rhs). not_shadows_vconsts rhs) rs"
  assumes vconstructor_value_rs: "vconstructor_value_rs rs"
  assumes vwelldefined_rs: "list_all (λ(_, rhs). vwelldefined rhs) rs"
begin

lemma map: "is_map (set rs)"
using distinct by (rule distinct_is_map)

end

abbreviation value_to_sterm_rules :: "vrule list ⇒ srule list" where
"value_to_sterm_rules ≡ map (map_prod id value_to_sterm)"

inductive (in special_constants)
  veval :: "(name × value) list ⇒ (name, value) fmap ⇒ sterm ⇒ value ⇒ bool"  (‹_, _/ ⊢v/ _ ↓/ _› [50,0,50] 50) for rs where
const: "(name, rhs) ∈ set rs ⟹ rs, Γ ⊢v Sconst name ↓ rhs" |
var: "fmlookup Γ name = Some val ⟹ rs, Γ ⊢v Svar name ↓ val" |
abs: "rs, Γ ⊢v Sabs cs ↓ Vabs cs Γ" |
comb: "
  rs, Γ ⊢v t ↓ Vabs cs Γ' ⟹ rs, Γ ⊢v u ↓ u' ⟹
  vfind_match cs u' = Some (env, _, rhs) ⟹
  rs, Γ' ++f env ⊢v rhs ↓ val ⟹
  rs, Γ ⊢v t $s u ↓ val" |
rec_comb: "
  rs, Γ ⊢v t ↓ Vrecabs css name Γ' ⟹
  fmlookup css name = Some cs ⟹
  rs, Γ ⊢v u ↓ u' ⟹
  vfind_match cs u' = Some (env, _, rhs) ⟹
  rs, Γ' ++f env ⊢v rhs ↓ val ⟹
  rs, Γ ⊢v t $s u ↓ val" |
constr: "
  name |∈| C ⟹
  list_all2 (veval rs Γ) ts us ⟹
  rs, Γ ⊢v name $$ ts ↓ Vconstr name us"

lemma (in vrules) veval_wellformed:
  assumes "rs, Γ ⊢v t ↓ v" "wellformed t" "wellformed_venv Γ"
  shows "vwellformed v"
using assms proof induction
  case const
  thus ?case
    using all_rules
    by (auto simp: list_all_iff)
next
  case comb
  show ?case
    apply (rule comb)
    using comb by (auto simp: list_all_iff dest: vfind_match_elem intro: vwellformed.vmatch_env)
next
  case (rec_comb Γ t css name Γ' cs u u' env pat rhs val)
  hence "(pat, rhs) ∈ set cs" "vmatch (mk_pat pat) u' = Some env"
    by (metis vfind_match_elem)+

  show ?case
    proof (rule rec_comb)
      have "wellformed t"
        using rec_comb by simp
      have "vwellformed (Vrecabs css name Γ')"
        by (rule rec_comb) fact+
      thus "wellformed rhs"
        using rec_comb ‹(pat, rhs) ∈ set cs›
        by (auto simp: list_all_iff)

      have "wellformed_venv Γ'"
        using ‹vwellformed (Vrecabs css name Γ')› by simp
      moreover have "wellformed_venv env"
        using rec_comb ‹vmatch (mk_pat pat) u' = Some env›
        by (auto intro: vwellformed.vmatch_env)
      ultimately show "wellformed_venv (Γ' ++f env)"
        by blast
    qed
next
  case (constr name Γ ts us)
  have "list_all vwellformed us"
    using ‹list_all2 _ _ _› ‹wellformed (list_comb _ _)›
    proof (induction ts us rule: list.rel_induct)
      case (Cons v vs u us)
      with constr show ?case
        unfolding wellformed.list_comb by auto
    qed simp
  thus ?case
    by (simp add: list_all_iff)
qed auto

lemma (in vrules) veval_closed:
  assumes "rs, Γ ⊢v t ↓ v" "closed_except t (fmdom Γ)" "closed_venv Γ"
  assumes "wellformed t" "wellformed_venv Γ"
  shows "vclosed v"
using assms proof induction
  case (const name rhs Γ)
  hence "(name, rhs) ∈ set rs"
    by (auto dest: map_of_SomeD)
  thus ?case
    using const all_rules
    by (auto simp: list_all_iff)
next
  case (comb Γ t cs Γ' u u' env pat rhs val)
  hence pat: "(pat, rhs) ∈ set cs" "vmatch (mk_pat pat) u' = Some env"
    by (metis vfind_match_elem)+

  show ?case
    proof (rule comb)
      have "vclosed u'"
        using comb by (auto simp: Sterm.closed_except_simps)
      have "closed_venv env"
        by (rule vclosed.vmatch_env) fact+
      thus "closed_venv (Γ' ++f env)"
        using comb by (auto simp: Sterm.closed_except_simps)
    next
      have "wellformed t"
        using comb by simp
      have "vwellformed (Vabs cs Γ')"
        by (rule veval_wellformed) fact+
      thus "wellformed rhs"
        using pat by (auto simp: list_all_iff)

      have "wellformed_venv Γ'"
        using ‹vwellformed (Vabs cs Γ')› by simp
      moreover have "wellformed_venv env"
        using comb pat
        by (auto intro: vwellformed.vmatch_env veval_wellformed)
      ultimately show "wellformed_venv (Γ' ++f env)"
        by blast

      have "vclosed (Vabs cs Γ')"
        using comb by (auto simp: Sterm.closed_except_simps)
      hence "closed_except rhs (fmdom Γ' |∪| frees pat)"
        using pat by (auto simp: list_all_iff)

      moreover have "fmdom env = frees pat"
        using ‹vwellformed (Vabs cs Γ')› pat
        by (auto simp: vmatch_dom mk_pat_frees list_all_iff)

      ultimately show "closed_except rhs (fmdom (Γ' ++f env))"
        using ‹vclosed (Vabs cs Γ')›
        by simp
    qed
next
  case (rec_comb Γ t css name Γ' cs u u' env pat rhs val)
  hence pat: "(pat, rhs) ∈ set cs" "vmatch (mk_pat pat) u' = Some env"
    by (metis vfind_match_elem)+

  show ?case
    proof (rule rec_comb)
      have "vclosed u'"
        using rec_comb by (auto simp: Sterm.closed_except_simps)
      have "closed_venv env"
        by (rule vclosed.vmatch_env) fact+
      thus "closed_venv (Γ' ++f env)"
        using rec_comb by (auto simp: Sterm.closed_except_simps)
    next
      have "wellformed t"
        using rec_comb by simp
      have "vwellformed (Vrecabs css name Γ')"
        by (rule veval_wellformed) fact+
      thus "wellformed rhs"
        using pat rec_comb by (auto simp: list_all_iff)

      have "wellformed_venv Γ'"
        using ‹vwellformed (Vrecabs css name Γ')› by simp
      moreover have "wellformed_venv env"
        using rec_comb pat
        by (auto intro: vwellformed.vmatch_env veval_wellformed)
      ultimately show "wellformed_venv (Γ' ++f env)"
        by blast

      have "wellformed_clauses cs"
        using ‹vwellformed (Vrecabs css name Γ')› ‹fmlookup css name = Some cs›
        by auto

      have "vclosed (Vrecabs css name Γ')"
        using rec_comb by (auto simp: Sterm.closed_except_simps)
      hence "closed_except rhs (fmdom Γ' |∪| frees pat)"
        using rec_comb pat by (auto simp: list_all_iff)
      moreover have "fmdom env = frees pat"
        using ‹wellformed_clauses cs› pat
        by (auto simp: list_all_iff vmatch_dom mk_pat_frees)
      ultimately show "closed_except rhs (fmdom (Γ' ++f env))"
        using ‹vclosed (Vrecabs css name Γ')›
        by simp
    qed
next
  case (constr name Γ ts us)
  have "list_all vclosed us"
    using ‹list_all2 _ _ _› ‹closed_except (_ $$ _) _› ‹wellformed (name $$ ts)›
    proof (induction ts us rule: list.rel_induct)
      case (Cons v vs u us)
      with constr show ?case
        unfolding closed.list_comb wellformed.list_comb
        by (auto simp: list_all_iff Sterm.closed_except_simps)
    qed simp
  thus ?case
    by (simp add: list_all_iff)
qed (auto simp: Sterm.closed_except_simps)

lemma (in vrules) veval_constructor_value:
  assumes "rs, Γ ⊢v t ↓ v" "vconstructor_value_env Γ"
  shows "vconstructor_value v"
using assms proof induction
  case (comb Γ t cs Γ' u u' env pat rhs val)
  hence "(pat, rhs) ∈ set cs" "vmatch (mk_pat pat) u' = Some env"
    by (metis vfind_match_elem)+
  hence "vconstructor_value_env (Γ' ++f env)"
    using comb by (auto intro: vconstructor_value.vmatch_env)
  thus ?case
    using comb by auto
next
  case (constr name Γ ts us)
  hence "list_all vconstructor_value us"
    by (auto elim: list_all2_rightE)
  with constr show ?case
    by simp
next
  case const
  thus ?case
    using vconstructor_value_rs
    by (auto simp: list_all_iff vconstructor_value_rs_def)
next
  case (rec_comb Γ t css name Γ' cs u u' env pat rhs val)
  hence "(pat, rhs) ∈ set cs" "vmatch (mk_pat pat) u' = Some env"
    by (metis vfind_match_elem)+
  hence "vconstructor_value_env (Γ' ++f env)"
    using rec_comb by (auto intro: vconstructor_value.vmatch_env)
  thus ?case
    using rec_comb by auto
qed (auto simp: list_all_iff vconstructor_value_rs_def)

lemma (in vrules) veval_welldefined:
  assumes "rs, Γ ⊢v t ↓ v" "fmpred (λ_. vwelldefined) Γ" "welldefined t"
  shows "vwelldefined v"
using assms proof induction
  case const
  thus ?case
    using vwelldefined_rs assms
    unfolding list_all_iff
    by (auto simp: list_all_iff)
next
  case (comb Γ t cs Γ' u u' env pat rhs val)
  hence "vwelldefined (Vabs cs Γ')"
    by auto

  show ?case
    proof (rule comb)
      have "fmpred (λ_. vwelldefined) Γ'"
        using ‹vwelldefined (Vabs cs Γ')›
        by simp
      moreover have "fmpred (λ_. vwelldefined) env"
        apply (rule vwelldefined.vmatch_env)
         apply (rule vfind_match_elem)
        using comb by auto
      ultimately show "fmpred (λ_. vwelldefined) (Γ' ++f env)"
        by auto
    next
      have "(pat, rhs) ∈ set cs"
        using comb by (metis vfind_match_elem)
      thus "welldefined rhs"
        using ‹vwelldefined (Vabs cs Γ')›
        by (auto simp: list_all_iff)
    qed
next
  case (rec_comb Γ t css name Γ' cs u u' env pat rhs val)
  have "(pat, rhs) ∈ set cs"
    by (rule vfind_match_elem) fact
  show ?case
    proof (rule rec_comb)
      show "fmpred (λ_. vwelldefined) (Γ' ++f env)"
        proof
          show "fmpred (λ_. vwelldefined) env"
            using rec_comb by (auto dest: vfind_match_elem intro: vwelldefined.vmatch_env)
        next
          show "fmpred (λ_. vwelldefined) Γ'"
            using rec_comb by auto
        qed
    next
      have "vwelldefined (Vrecabs css name Γ')"
        using rec_comb by auto

      thus "welldefined rhs"
        apply simp
        apply (elim conjE)
        apply (drule fmpredD[where m = css])
        using ‹(pat, rhs) ∈ set cs› rec_comb by (auto simp: list_all_iff)
    qed
next
  case (constr name Γ ts us)
  have "list_all vwelldefined us"
    using ‹list_all2 _ _ _› ‹welldefined (_ $$ _)›
    proof (induction ts us rule: list.rel_induct)
      case (Cons v vs u us)
      with constr show ?case
        unfolding welldefined.list_comb
        by auto
    qed simp
  with constr show ?case
    by (simp add: list_all_iff all_consts_def)
next
  case abs
  thus ?case
    unfolding welldefined_sabs by auto
qed auto

subsubsection ‹Correctness wrt @{const constructors.seval}›

context vrules begin

definition rs' :: "srule list" where
"rs' = value_to_sterm_rules rs"

lemma value_to_sterm_srules: "srules C_info rs'"
proof
  show "distinct (map fst rs')"
    unfolding rs'_def
    using distinct by auto
next
  show "list_all srule rs'"
    unfolding rs'_def list.pred_map
    apply (rule list.pred_mono_strong[OF all_rules])
    apply (auto intro: vclosed.value_to_sterm vwellformed.value_to_sterm)
    subgoal by (auto intro: vwellformed.value_to_sterm)
    subgoal by (auto intro: vclosed.value_to_sterm)
    subgoal for a b by (cases b) (auto simp: is_abs_def term_cases_def)
    done
next
  show "fdisjnt (fst |`| fset_of_list rs') C"
    using vconstructor_value_rs unfolding rs'_def vconstructor_value_rs_def
    by auto
  interpret c: constants _ "fst |`| fset_of_list rs'"
    by standard (fact | fact distinct_ctr)+
  have all_consts: "c.all_consts = all_consts"
    unfolding c.all_consts_def all_consts_def
    by (simp add: rs'_def)
  have shadows_consts: "c.shadows_consts rhs = shadows_consts rhs" for rhs :: sterm
    by (induction rhs; fastforce simp: all_consts list_ex_iff)

  have "list_all (λ(_, rhs). ¬ shadows_consts rhs) rs'"
    unfolding rs'_def
    unfolding list.pred_map map_prod_def id_def case_prod_twice list_all_iff
    apply auto
    unfolding comp_def all_consts_def
    using not_shadows
    by (fastforce simp: list_all_iff dest: not_shadows_vconsts.value_to_sterm)
  thus "list_all (λ(_, rhs). ¬ c.shadows_consts rhs) rs'"
    unfolding shadows_consts .

  have "list_all (λ(_, rhs). welldefined rhs) rs'"
    unfolding rs'_def list.pred_map
    apply (rule list.pred_mono_strong[OF vwelldefined_rs])
    subgoal for z
      apply (cases z; hypsubst_thin)
      apply simp
      apply (erule vwelldefined.value_to_sterm)
      done
    done
  moreover have "map fst rs = map fst rs'"
    unfolding rs'_def by simp
  ultimately have "list_all (λ(_, rhs). welldefined rhs) rs'"
    by simp
  thus "list_all (λ(_, rhs). c.welldefined rhs) rs'"
    unfolding all_consts .
next
  show "distinct all_constructors"
    by (fact distinct_ctr)
qed

end

text (in special_constants) ‹
  When we evaluate @{typ sterm}s using @{const veval}, the result is a @{typ value} which possibly
  contains a closure (constructor @{const Vabs}). Such a closure is essentially a case-lambda (like
  @{const Sabs}), but with an additionally captured environment of type
  @{typ [source] "string ⇀ value"} (which is usually called ‹Γ'›). The contained case-lambda might
  not be closed.

  The proof idea is that we can always substitute with ‹Γ'› and obtain a regular @{typ sterm} value.
  The only interesting part of the proof is the case when a case-lambda gets applied to a value,
  because in that process, a hidden environment is ∗‹unveiled›. That environment may not bear any
  relation to the active environment ‹Γ› at all. But pattern matching and substitution proceeds only
  with that hidden environment.
›

context vrules begin

context begin

private lemma veval_correct0:
  assumes "rs, Γ ⊢v t ↓ v" "wellformed t" "wellformed_venv Γ"
  assumes "closed_except t (fmdom Γ)" "closed_venv Γ"
  assumes "vconstructor_value_env Γ"
  shows "rs', fmmap value_to_sterm Γ ⊢s t ↓ value_to_sterm v"
using assms proof induction
  case (constr name Γ ts us)

  have "list_all2 (seval rs' (fmmap value_to_sterm Γ)) ts (map value_to_sterm us)"
    unfolding list_all2_map2
    proof (rule list.rel_mono_strong[OF ‹list_all2 _ _ _›], elim conjE impE)
      fix t u
      assume "t ∈ set ts" "u ∈ set us"
      assume "rs, Γ ⊢v t ↓ u"

      show "wellformed t"  "closed_except t (fmdom Γ)"
        using ‹t ∈ set ts› constr
        unfolding wellformed.list_comb closed.list_comb list_all_iff
        by auto
    qed (rule constr | assumption)+

  thus ?case
    using ‹name |∈| C›
    by (auto intro: seval.constr)
next
  case (comb Γ t cs Γ' u u' venv pat rhs val)

  ― ‹We first need to establish a ton of boring side-conditions.›

  hence "vmatch (mk_pat pat) u' = Some venv"
    by (auto dest: vfind_match_elem)

  have "wellformed t"
    using comb by simp
  have "vwellformed (Vabs cs Γ')"
    by (rule veval_wellformed) fact+

  hence
    "list_all (linear ∘ fst) cs"
    "wellformed_venv Γ'"
    by (auto simp: list_all_iff split_beta)

  have "rel_option match_related (vfind_match cs u') (find_match cs (value_to_sterm u'))"
    apply (rule find_match_eq)
     apply fact
    apply (rule veval_constructor_value)
     apply fact+
    done

  then obtain senv
    where "find_match cs (value_to_sterm u') = Some (senv, pat, rhs)"
      and "env_eq venv senv"
    using ‹vfind_match _ _ = _›
    by cases auto
  hence "(pat, rhs) ∈ set cs" "match pat (value_to_sterm u') = Some senv"
    by (auto dest: find_match_elem)
  hence "fmdom senv = frees pat"
    by (simp add: match_dom)

  moreover have "senv = fmmap value_to_sterm venv"
    using ‹env_eq venv senv›
    by (rule env_eq_eq)

  ultimately have "fmdom venv = frees pat"
    by simp

  have "closed_except t (fmdom Γ)" "wellformed t"
    using comb by (simp add: closed_except_def)+
  have "vclosed (Vabs cs Γ')"
    by (rule veval_closed) fact+

  have "vconstructor_value (Vabs cs Γ')" "vconstructor_value u'"
    by (rule veval_constructor_value; fact)+
  hence "vconstructor_value_env Γ'"
    by simp
  have "vconstructor_value_env venv"
    by (rule vconstructor_value.vmatch_env) fact+

  have "wellformed u"
    using comb by simp
  have "vwellformed u'"
    by (rule veval_wellformed) fact+
  have "wellformed_venv venv"
    by (rule vwellformed.vmatch_env) fact+

  have "closed_except u (fmdom Γ)"
    using comb by (simp add: closed_except_def)
  have "vclosed u'"
    by (rule veval_closed) fact+
  have "closed_venv venv"
    by (rule vclosed.vmatch_env) fact+

  have "closed_venv Γ'"
    using ‹vclosed (Vabs cs Γ')› by simp

  let ?subst = "λpat t. subst t (fmdrop_fset (frees pat) (fmmap value_to_sterm Γ'))"
  txt ‹
    ▸ We know the following (induction hypothesis):
      @{term "rs', fmmap value_to_sterm (Γ' ++f venv) ⊢s rhs ↓ value_to_sterm val"}

    ▸ ... first, we can deduce using @{thm [source] ssubst_eval} that this is equivalent to
      substituting ‹rhs› first:
      @{term "rs', fmmap value_to_sterm (Γ' ++f venv) ⊢s ?subst pat rhs ↓ value_to_sterm val"}

    ▸ ... second, we can replace the hidden environment ‹Γ'› by the active environment ‹Γ›
      using @{thm [source] seval_agree_eq} because it does not contain useful information at this
      point:
      @{term "rs', fmmap value_to_sterm (Γ ++f venv) ⊢s ?subst pat rhs ↓ value_to_sterm val"}

    ▸ ... finally we can apply a step in the original semantics and arrive at the conclusion:
      @{term "rs', fmmap value_to_sterm Γ ⊢s t $s u ↓ value_to_sterm val"}
  ›

  have "rs', fmmap value_to_sterm (Γ' ++f venv) ⊢s ?subst pat rhs ↓ value_to_sterm val"
    proof (rule ssubst_eval)
      show "rs', fmmap value_to_sterm (Γ' ++f venv) ⊢s rhs ↓ value_to_sterm val"
        proof (rule comb)
          have "linear pat" "closed_except rhs (fmdom Γ' |∪| frees pat)"
            using ‹(pat, rhs) ∈ set cs› ‹vwellformed (Vabs cs Γ')› ‹vclosed (Vabs cs Γ')›
            by (auto simp: list_all_iff)
          hence "closed_except rhs (fmdom Γ' |∪| fmdom venv)"
            using ‹vmatch (mk_pat pat) u' = Some venv›
            by (auto simp: mk_pat_frees vmatch_dom)
          thus "closed_except rhs (fmdom (Γ' ++f venv))"
            by simp
        next
          show "wellformed_venv (Γ' ++f venv)"
            using ‹wellformed_venv Γ'› ‹wellformed_venv venv›
            by blast
        next
          show "closed_venv (Γ' ++f venv)"
            using ‹closed_venv Γ'› ‹closed_venv venv›
            by blast
        next
          show "vconstructor_value_env (Γ' ++f venv)"
            using ‹vconstructor_value_env Γ'› ‹vconstructor_value_env venv›
            by blast
        next
          show "wellformed rhs"
            using ‹(pat, rhs) ∈ set cs› ‹vwellformed (Vabs cs Γ')›
            by (fastforce simp: list_all_iff)
        qed
    next
      have "fmdrop_fset (fmdom venv) Γ' ⊆f Γ' ++f venv"
        including fmap.lifting and fset.lifting
        by transfer'
           (auto simp: map_drop_set_def map_filter_def map_le_def map_add_def split: if_splits)
      thus "fmdrop_fset (frees pat) (fmmap value_to_sterm Γ') ⊆f fmmap value_to_sterm (Γ' ++f venv)"
        unfolding ‹fmdom venv = frees pat›
        by (metis fmdrop_fset_fmmap fmmap_subset)
    next
      show "closed_env (fmmap value_to_sterm (Γ' ++f venv))"
        apply auto
        apply rule
         apply (rule vclosed.value_to_sterm_env, fact)+
        done
    next
      show "value_env (fmmap value_to_sterm (Γ' ++f venv))"
        apply auto
        apply rule
         apply (rule vconstructor_value.value_to_sterm_env, fact)+
        done
    qed

  show ?case
    proof (rule seval.comb)
      have "rs', fmmap value_to_sterm Γ ⊢s t ↓ value_to_sterm (Vabs cs Γ')"
        using comb by (auto simp: closed_except_def)
      thus "rs', fmmap value_to_sterm Γ ⊢s t ↓ Sabs (map (λ(pat, t). (pat, ?subst pat t)) cs)"
        by simp
    next
      show "rs', fmmap value_to_sterm Γ ⊢s u ↓ value_to_sterm u'"
        using comb by (simp add: closed_except_def)
    next
      show "rs', fmmap value_to_sterm Γ ++f senv ⊢s ?subst pat rhs ↓ value_to_sterm val"
        proof (rule seval_agree_eq)
          show "rs', fmmap value_to_sterm Γ' ++f fmmap value_to_sterm venv ⊢s ?subst pat rhs ↓ value_to_sterm val"
            using ‹rs', fmmap value_to_sterm (Γ' ++f venv) ⊢s ?subst pat rhs ↓ value_to_sterm val› by simp
        next
          show "fmrestrict_fset (frees pat) (fmmap value_to_sterm Γ' ++f fmmap value_to_sterm venv) =
                fmrestrict_fset (frees pat) (fmmap value_to_sterm Γ ++f senv)"
            unfolding ‹senv = _›
            apply (subst ‹fmdom venv = frees pat›[symmetric])+
            apply (subst fmdom_map[symmetric])
            apply (subst fmadd_restrict_right_dom)
            apply (subst fmdom_map[symmetric])
            apply (subst fmadd_restrict_right_dom)
            apply simp
            done
        next
          have "closed (value_to_sterm (Vabs cs Γ'))"
            using ‹vclosed (Vabs cs Γ')›
            by (rule vclosed.value_to_sterm)
          thus "closed_except (subst rhs (fmdrop_fset (frees pat) (fmmap value_to_sterm Γ'))) (frees pat)"
            using ‹(pat, rhs) ∈ set cs›
            by (auto simp: Sterm.closed_except_simps list_all_iff)
        next
          show "closed_env (fmmap value_to_sterm Γ' ++f fmmap value_to_sterm venv)"
            using ‹closed_venv Γ'› ‹closed_venv venv›
            by (auto intro: vclosed.value_to_sterm_env)
        next
          show "frees pat |⊆| fmdom (fmmap value_to_sterm Γ' ++f fmmap value_to_sterm venv)"
            using ‹fmdom venv = frees pat›
            by fastforce
        next
          show "closed_srules rs'"
            using all_rules
            unfolding rs'_def list_all_iff
            by (fastforce intro: vclosed.value_to_sterm)
        qed
    next
      show "find_match (map (λ(pat, t). (pat, ?subst pat t)) cs) (value_to_sterm u') = Some (senv, pat, ?subst pat rhs)"
        using ‹find_match _ _ = _›
        by (auto simp: find_match_map)
    qed
next
  ― ‹Basically a verbatim copy from the ‹comb› case›

  case (rec_comb Γ t css name Γ' cs u u' venv pat rhs val)

  hence "vmatch (mk_pat pat) u' = Some venv"
    by (auto dest: vfind_match_elem)

  have "cs = the (fmlookup css name)"
    using rec_comb by simp

  have "wellformed t"
    using rec_comb by simp
  have "vwellformed (Vrecabs css name Γ')"
    by (rule veval_wellformed) fact+
  hence "vwellformed (Vabs cs Γ')" ― ‹convenient hack: @{term cs} is not really part of a @{term Vabs}›
    using rec_comb by auto

  hence
    "list_all (linear ∘ fst) cs"
    "wellformed_venv Γ'"
    by (auto simp: list_all_iff split_beta)

  have "rel_option match_related (vfind_match cs u') (find_match cs (value_to_sterm u'))"
    apply (rule find_match_eq)
     apply fact
    apply (rule veval_constructor_value)
     apply fact+
    done

  then obtain senv
    where "find_match cs (value_to_sterm u') = Some (senv, pat, rhs)"
      and "env_eq venv senv"
    using ‹vfind_match _ _ = _›
    by cases auto
  hence "(pat, rhs) ∈ set cs" "match pat (value_to_sterm u') = Some senv"
    by (auto dest: find_match_elem)
  hence "fmdom senv = frees pat"
    by (simp add: match_dom)

  moreover have "senv = fmmap value_to_sterm venv"
    using ‹env_eq venv senv›
    by (rule env_eq_eq)

  ultimately have "fmdom venv = frees pat"
    by simp

  have "closed_except t (fmdom Γ)" "wellformed t"
    using rec_comb by (simp add: closed_except_def)+
  have "vclosed (Vrecabs css name Γ')"
    by (rule veval_closed) fact+
  hence "vclosed (Vabs cs Γ')"
    using rec_comb by auto

  have "vconstructor_value u'"
    by (rule veval_constructor_value) fact+
  have "vconstructor_value (Vrecabs css name Γ')"
    by (rule veval_constructor_value) fact+
  hence "vconstructor_value_env Γ'"
    by simp
  have "vconstructor_value_env venv"
    by (rule vconstructor_value.vmatch_env) fact+

  have "wellformed u"
    using rec_comb by simp
  have "vwellformed u'"
    by (rule veval_wellformed) fact+
  have "wellformed_venv venv"
    by (rule vwellformed.vmatch_env) fact+

  have "closed_except u (fmdom Γ)"
    using rec_comb by (simp add: closed_except_def)
  have "vclosed u'"
    by (rule veval_closed) fact+
  have "closed_venv venv"
    by (rule vclosed.vmatch_env) fact+

  have "closed_venv Γ'"
    using ‹vclosed (Vabs cs Γ')› by simp

  let ?subst = "λpat t. subst t (fmdrop_fset (frees pat) (fmmap value_to_sterm Γ'))"
  have "rs', fmmap value_to_sterm (Γ' ++f venv) ⊢s ?subst pat rhs ↓ value_to_sterm val"
    proof (rule ssubst_eval)
      show "rs', fmmap value_to_sterm (Γ' ++f venv) ⊢s rhs ↓ value_to_sterm val"
        proof (rule rec_comb)
          have "linear pat" "closed_except rhs (fmdom Γ' |∪| frees pat)"
            using ‹(pat, rhs) ∈ set cs› ‹vwellformed (Vabs cs Γ')› ‹vclosed (Vabs cs Γ')›
            by (auto simp: list_all_iff)
          hence "closed_except rhs (fmdom Γ' |∪| fmdom venv)"
            using ‹vmatch (mk_pat pat) u' = Some venv›
            by (auto simp: mk_pat_frees vmatch_dom)
          thus "closed_except rhs (fmdom (Γ' ++f venv))"
            by simp
        next
          show "wellformed_venv (Γ' ++f venv)"
            using ‹wellformed_venv Γ'› ‹wellformed_venv venv›
            by blast
        next
          show "closed_venv (Γ' ++f venv)"
            using ‹closed_venv Γ'› ‹closed_venv venv›
            by blast
        next
          show "vconstructor_value_env (Γ' ++f venv)"
            using ‹vconstructor_value_env Γ'› ‹vconstructor_value_env venv›
            by blast
        next
          show "wellformed rhs"
            using ‹(pat, rhs) ∈ set cs› ‹vwellformed (Vabs cs Γ')›
            by (fastforce simp: list_all_iff)
        qed
    next
      have "fmdrop_fset (fmdom venv) Γ' ⊆f Γ' ++f venv"
        including fmap.lifting and fset.lifting
        by transfer'
           (auto simp: map_drop_set_def map_filter_def map_le_def map_add_def split: if_splits)
      thus "fmdrop_fset (frees pat) (fmmap value_to_sterm Γ') ⊆f fmmap value_to_sterm (Γ' ++f venv)"
        unfolding ‹fmdom venv = frees pat›
        by (metis fmdrop_fset_fmmap fmmap_subset)
    next
      show "closed_env (fmmap value_to_sterm (Γ' ++f venv))"
        apply auto
        apply rule
         apply (rule vclosed.value_to_sterm_env, fact)+
        done
    next
      show "value_env (fmmap value_to_sterm (Γ' ++f venv))"
        apply auto
        apply rule
         apply (rule vconstructor_value.value_to_sterm_env, fact)+
        done
    qed

  show ?case
    proof (rule seval.comb)
      have "rs', fmmap value_to_sterm Γ ⊢s t ↓ value_to_sterm (Vrecabs css name Γ')"
        using rec_comb by (auto simp: closed_except_def)
      thus "rs', fmmap value_to_sterm Γ ⊢s t ↓ Sabs (map (λ(pat, t). (pat, ?subst pat t)) cs)"
        unfolding ‹cs = _› by simp
    next
      show "rs', fmmap value_to_sterm Γ ⊢s u ↓ value_to_sterm u'"
        using rec_comb by (simp add: closed_except_def)
    next
      show "rs', fmmap value_to_sterm Γ ++f senv ⊢s ?subst pat rhs ↓ value_to_sterm val"
        proof (rule seval_agree_eq)
          show "rs', fmmap value_to_sterm Γ' ++f fmmap value_to_sterm venv ⊢s ?subst pat rhs ↓ value_to_sterm val"
            using ‹rs', fmmap value_to_sterm (Γ' ++f venv) ⊢s ?subst pat rhs ↓ value_to_sterm val› by simp
        next
          show "fmrestrict_fset (frees pat) (fmmap value_to_sterm Γ' ++f fmmap value_to_sterm venv) =
                fmrestrict_fset (frees pat) (fmmap value_to_sterm Γ ++f senv)"
            unfolding ‹senv = _›
            apply (subst ‹fmdom venv = frees pat›[symmetric])+
            apply (subst fmdom_map[symmetric])
            apply (subst fmadd_restrict_right_dom)
            apply (subst fmdom_map[symmetric])
            apply (subst fmadd_restrict_right_dom)
            apply simp
            done
        next
          have "closed (value_to_sterm (Vabs cs Γ'))"
            using ‹vclosed (Vabs cs Γ')›
            by (rule vclosed.value_to_sterm)
          thus "closed_except (subst rhs (fmdrop_fset (frees pat) (fmmap value_to_sterm Γ'))) (frees pat)"
            using ‹(pat, rhs) ∈ set cs›
            by (auto simp: Sterm.closed_except_simps list_all_iff)
        next
          show "closed_env (fmmap value_to_sterm Γ' ++f fmmap value_to_sterm venv)"
            using ‹closed_venv Γ'› ‹closed_venv venv›
            by (auto intro: vclosed.value_to_sterm_env)
        next
          show "frees pat |⊆| fmdom (fmmap value_to_sterm Γ' ++f fmmap value_to_sterm venv)"
            using ‹fmdom venv = frees pat›
            by fastforce
        next
          show "closed_srules rs'"
            using all_rules
            unfolding rs'_def list_all_iff
            by (fastforce intro: vclosed.value_to_sterm)
        qed
    next
      show "find_match (map (λ(pat, t). (pat, ?subst pat t)) cs) (value_to_sterm u') = Some (senv, pat, ?subst pat rhs)"
        using ‹find_match _ _ = _›
        by (auto simp: find_match_map)
    qed
next
  case (const name rhs Γ)
  show ?case
    apply (rule seval.const)
    unfolding rs'_def
    using ‹(name, rhs) ∈ _› by force
next
  case abs
  show ?case
    by (auto simp del: fmdrop_fset_fmmap intro: seval.abs)
qed (auto intro: seval.var seval.abs)

lemma veval_correct:
  assumes "rs, fmempty ⊢v t ↓ v" "wellformed t" "closed t"
  shows "rs', fmempty ⊢s t ↓ value_to_sterm v"
proof -
  have "rs', fmmap value_to_sterm fmempty ⊢s t ↓ value_to_sterm v"
    using assms
    by (auto intro: veval_correct0 simp del: fmmap_empty)
  thus ?thesis
    by simp
qed

end end

end