(* * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) * * SPDX-License-Identifier: BSD-2-Clause *) (* * ShowTypes: show "hidden" type constraints in terms. * This is a simple utility around Sledgehammer's type annotation code. * * Based on Sledgehammer_Isar_Annotate and related modules * (by Blanchette and Smolka). * * * Usage * ---- * This theory provides the improper commands * term_show_types * thm_show_types [ ...] * goal_show_types [N] * as well as the ML function Show_Types.term_show_types. * * term_show_types and thm_show_types can be used as replacements * for the term and thm commands. * * * Known issues * ---- * \ Type constraints for variables, etc. are not always printed. * In that case, set show_types/show_sorts to get extra annotations. * * \ Doesn't print sort constraints. show_sorts will print them but * the output may not be formatted properly. * * \ Doesn't compose with other term-display utils like Insulin. *) theory ShowTypes imports Main keywords "term_show_types" "thm_show_types" "goal_show_types" :: diag begin ML \ structure Show_Types = struct fun pretty_markup_to_string no_markup = Pretty.string_of #> YXML.parse_body #> (if no_markup then XML.content_of else YXML.string_of_body) fun term_show_types no_markup ctxt term = let val ctxt' = ctxt |> Config.put show_markup false |> Config.put Printer.show_type_emphasis false (* FIXME: the sledgehammer code also sets these, * but do we always want to force them on the user? *) (* |> Config.put show_types false |> Config.put show_sorts false |> Config.put show_consts false *) |> Proof_Context.augment term in singleton (Syntax.uncheck_terms ctxt') term |> Sledgehammer_Isar_Annotate.annotate_types_in_term ctxt' |> Syntax.unparse_term ctxt' |> pretty_markup_to_string no_markup end fun goal_show_types no_markup ctxt goal n = let val subgoals = goal |> Thm.prems_of val subgoals = if n = 0 then subgoals else if n < 1 orelse n > length subgoals then (* trigger error *) [Logic.get_goal (Thm.term_of (Thm.cprop_of goal)) n] else [nth subgoals (n - 1)] val results = map (fn t => (NONE, term_show_types no_markup ctxt t) handle ex as TERM _ => (SOME ex, term_show_types no_markup ctxt t)) subgoals in if null results then error "No subgoals to show" else if forall (Option.isSome o fst) results then raise the (fst (hd results)) else map snd results end end; Outer_Syntax.command @{command_keyword term_show_types} "term_show_types TERM -> show TERM with type annotations" (Parse.term >> (fn t => Toplevel.keep (fn state => let val ctxt = Toplevel.context_of state in Show_Types.term_show_types false ctxt (Syntax.read_term ctxt t) |> writeln end))); Outer_Syntax.command @{command_keyword thm_show_types} "thm_show_types THM1 THM2 ... -> show theorems with type annotations" (Parse.thms1 >> (fn ts => Toplevel.keep (fn state => let val ctxt = Toplevel.context_of state in Attrib.eval_thms ctxt ts |> app (Thm.prop_of #> Show_Types.term_show_types false ctxt #> writeln) end))); let fun print_subgoals (x::xs) n = (writeln (Int.toString n ^ ". " ^ x); print_subgoals xs (n+1)) | print_subgoals [] _ = (); in Outer_Syntax.command @{command_keyword goal_show_types} "goal_show_types [N] -> show subgoals (or Nth goal) with type annotations" (Scan.option Parse.int >> (fn n => Toplevel.keep (fn state => let val ctxt = Toplevel.context_of state val goal = Toplevel.proof_of state |> Proof.raw_goal |> #goal in Show_Types.goal_show_types false ctxt goal (Option.getOpt (n, 0)) |> (fn xs => case xs of [x] => writeln x | _ => print_subgoals xs 1) end))) end; \ end