aboutsummaryrefslogtreecommitdiff
path: root/spartan/core/elaboration.ML
blob: 9e5e0bd156c0db006ef78e8eb825b19645b8ca1c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
(*  Title:      elaboration.ML
    Author:     Joshua Chen

Basic term elaboration.
*)

structure Elab: sig

val elab: Proof.context -> cterm list -> term -> Envir.env
val elab_stmt: Proof.context -> cterm list -> term -> Envir.env * term
val elaborate: Proof.context -> cterm list -> ('a * (term * term list) list) list -> ('a * (term * term list) list) list

end = struct

(*Elaborate `tm` by solving the inference problem `tm: {}`, knowing `assums`,
  which are fully elaborated, in `ctxt`. Return a substitution.*)
fun elab ctxt assums tm =
  if Lib.no_vars tm
  then Envir.init
  else
    let
      val inf = Goal.init (Thm.cterm_of ctxt (Lib.typing_of_term tm))
      val res = Types.check_infer (map Thm.assume assums) 1 (ctxt, inf)
      val tm' =
        Thm.prop_of (#2 (Seq.hd (Seq.filter_results res)))
        |> Lib.dest_prop |> Lib.term_of_typing
        handle TERM ("dest_typing", [t]) =>
          let val typ = Logic.unprotect (Logic.strip_assums_concl t)
            |> Lib.term_of_typing
          in
            error ("Elaboration of " ^ Syntax.string_of_term ctxt typ ^ " failed")
          end
    in
      Seq.hd (Unify.matchers (Context.Proof ctxt) [(tm, tm')])
    end
    handle Option => error
      ("Elaboration of " ^ Syntax.string_of_term ctxt tm ^ " failed")

(*Recursively elaborate a statement \<And>x ... y. \<lbrakk>...\<rbrakk> \<Longrightarrow> P x ... y by elaborating
  only the types of typing judgments (in particular, does not look at judgmental
  equality statements). Could also elaborate the terms of typing judgments, but
  for now we assume that these are always free variables in all the cases we're
  interested in.*)
fun elab_stmt ctxt assums stmt =
  let
    val stmt = Lib.dest_prop stmt
    fun subst_term env = Envir.subst_term (Envir.type_env env, Envir.term_env env)
  in
    if Lib.no_vars stmt orelse Lib.is_eq stmt then
      (Envir.init, stmt)
    else if Lib.is_typing stmt then
      let
        val typ = Lib.type_of_typing stmt
        val subst = elab ctxt assums typ
      in (subst, subst_term subst stmt) end
    else
      let
        fun elab' assums (x :: xs) =
              let
                val (env, x') = elab_stmt ctxt assums x
                val assums' =
                  if Lib.no_vars x' then Thm.cterm_of ctxt x' :: assums else assums
              in env :: elab' assums' xs end
          | elab' _ [] = []
        val (prems, concl) = Lib.decompose_goal ctxt stmt
        val subst = fold (curry Envir.merge) (elab' assums prems) Envir.init
        val prems' = map (Thm.cterm_of ctxt o subst_term subst) prems
        val subst' =
          if Lib.is_typing concl then
            let val typ = Lib.type_of_typing concl
            in Envir.merge (subst, elab ctxt (assums @ prems') typ) end
          else subst
      in (subst', subst_term subst' stmt) end
  end

(*Apply elaboration to the list format that assumptions and goal statements are
  given in*)
fun elaborate ctxt known assms =
  let
    fun subst_term env = Envir.subst_term (Envir.type_env env, Envir.term_env env)
    fun elab_fact (fact, xs) assums =
      let val (subst, fact') = elab_stmt ctxt assums fact in
        ((fact', map (subst_term subst) xs), Thm.cterm_of ctxt fact' :: assums)
      end
    fun elab (b, facts) assums =
      let val (facts', assums') = fold_map elab_fact facts assums
      in ((b, facts'), assums') end
  in #1 (fold_map elab assms known) end


end