src/HOL/Tools/Nitpick/nitpick_mono.ML
author blanchet
Wed Jan 20 10:38:06 2010 +0100 (2010-01-20)
changeset 34936 c4f04bee79f3
parent 34123 c4988215a691
child 34982 7b8c366e34a2
permissions -rw-r--r--
some work on Nitpick's support for quotient types;
quotient types are not yet in Isabelle, so for now I hardcoded "IntEx.my_int"
     1 (*  Title:      HOL/Tools/Nitpick/nitpick_mono.ML
     2     Author:     Jasmin Blanchette, TU Muenchen
     3     Copyright   2009
     4 
     5 Monotonicity predicate for higher-order logic.
     6 *)
     7 
     8 signature NITPICK_MONO =
     9 sig
    10   type extended_context = Nitpick_HOL.extended_context
    11 
    12   val formulas_monotonic :
    13     extended_context -> typ -> term list -> term list -> term -> bool
    14 end;
    15 
    16 structure Nitpick_Mono : NITPICK_MONO =
    17 struct
    18 
    19 open Nitpick_Util
    20 open Nitpick_HOL
    21 
    22 type var = int
    23 
    24 datatype sign = Pos | Neg
    25 datatype sign_atom = S of sign | V of var
    26 
    27 type literal = var * sign
    28 
    29 datatype ctype =
    30   CAlpha |
    31   CFun of ctype * sign_atom * ctype |
    32   CPair of ctype * ctype |
    33   CType of string * ctype list |
    34   CRec of string * typ list
    35 
    36 type cdata =
    37   {ext_ctxt: extended_context,
    38    alpha_T: typ,
    39    max_fresh: int Unsynchronized.ref,
    40    datatype_cache: ((string * typ list) * ctype) list Unsynchronized.ref,
    41    constr_cache: (styp * ctype) list Unsynchronized.ref}
    42 
    43 exception CTYPE of string * ctype list
    44 
    45 (* string -> unit *)
    46 fun print_g (s : string) = ()
    47 
    48 (* var -> string *)
    49 val string_for_var = signed_string_of_int
    50 (* string -> var list -> string *)
    51 fun string_for_vars sep [] = "0\<^bsub>" ^ sep ^ "\<^esub>"
    52   | string_for_vars sep xs = space_implode sep (map string_for_var xs)
    53 fun subscript_string_for_vars sep xs =
    54   if null xs then "" else "\<^bsub>" ^ string_for_vars sep xs ^ "\<^esub>"
    55 
    56 (* sign -> string *)
    57 fun string_for_sign Pos = "+"
    58   | string_for_sign Neg = "-"
    59 
    60 (* sign -> sign -> sign *)
    61 fun xor sn1 sn2 = if sn1 = sn2 then Pos else Neg
    62 (* sign -> sign *)
    63 val negate = xor Neg
    64 
    65 (* sign_atom -> string *)
    66 fun string_for_sign_atom (S sn) = string_for_sign sn
    67   | string_for_sign_atom (V j) = string_for_var j
    68 
    69 (* literal -> string *)
    70 fun string_for_literal (x, sn) = string_for_var x ^ " = " ^ string_for_sign sn
    71 
    72 val bool_C = CType (@{type_name bool}, [])
    73 
    74 (* ctype -> bool *)
    75 fun is_CRec (CRec _) = true
    76   | is_CRec _ = false
    77 
    78 val no_prec = 100
    79 val prec_CFun = 1
    80 val prec_CPair = 2
    81 
    82 (* tuple_set -> int *)
    83 fun precedence_of_ctype (CFun _) = prec_CFun
    84   | precedence_of_ctype (CPair _) = prec_CPair
    85   | precedence_of_ctype _ = no_prec
    86 
    87 (* ctype -> string *)
    88 val string_for_ctype =
    89   let
    90     (* int -> ctype -> string *)
    91     fun aux outer_prec C =
    92       let
    93         val prec = precedence_of_ctype C
    94         val need_parens = (prec < outer_prec)
    95       in
    96         (if need_parens then "(" else "") ^
    97         (case C of
    98            CAlpha => "\<alpha>"
    99          | CFun (C1, a, C2) =>
   100            aux (prec + 1) C1 ^ " \<Rightarrow>\<^bsup>" ^
   101            string_for_sign_atom a ^ "\<^esup> " ^ aux prec C2
   102          | CPair (C1, C2) => aux (prec + 1) C1 ^ " \<times> " ^ aux prec C2
   103          | CType (s, []) =>
   104            if s = @{type_name prop} orelse s = @{type_name bool} then "o" else s
   105          | CType (s, Cs) => "(" ^ commas (map (aux 0) Cs) ^ ") " ^ s
   106          | CRec (s, _) => "[" ^ s ^ "]") ^
   107         (if need_parens then ")" else "")
   108       end
   109   in aux 0 end
   110 
   111 (* ctype -> ctype list *)
   112 fun flatten_ctype (CPair (C1, C2)) = maps flatten_ctype [C1, C2]
   113   | flatten_ctype (CType (_, Cs)) = maps flatten_ctype Cs
   114   | flatten_ctype C = [C]
   115 
   116 (* extended_context -> typ -> cdata *)
   117 fun initial_cdata ext_ctxt alpha_T =
   118   ({ext_ctxt = ext_ctxt, alpha_T = alpha_T, max_fresh = Unsynchronized.ref 0,
   119     datatype_cache = Unsynchronized.ref [],
   120     constr_cache = Unsynchronized.ref []} : cdata)
   121 
   122 (* typ -> typ -> bool *)
   123 fun could_exist_alpha_subtype alpha_T (T as Type (_, Ts)) =
   124     T = alpha_T orelse (not (is_fp_iterator_type T) andalso
   125                         exists (could_exist_alpha_subtype alpha_T) Ts)
   126   | could_exist_alpha_subtype alpha_T T = (T = alpha_T)
   127 (* theory -> typ -> typ -> bool *)
   128 fun could_exist_alpha_sub_ctype _ (alpha_T as TFree _) T =
   129     could_exist_alpha_subtype alpha_T T
   130   | could_exist_alpha_sub_ctype thy alpha_T T =
   131     (T = alpha_T orelse is_datatype thy T)
   132 
   133 (* ctype -> bool *)
   134 fun exists_alpha_sub_ctype CAlpha = true
   135   | exists_alpha_sub_ctype (CFun (C1, _, C2)) =
   136     exists exists_alpha_sub_ctype [C1, C2]
   137   | exists_alpha_sub_ctype (CPair (C1, C2)) =
   138     exists exists_alpha_sub_ctype [C1, C2]
   139   | exists_alpha_sub_ctype (CType (_, Cs)) = exists exists_alpha_sub_ctype Cs
   140   | exists_alpha_sub_ctype (CRec _) = true
   141 
   142 (* ctype -> bool *)
   143 fun exists_alpha_sub_ctype_fresh CAlpha = true
   144   | exists_alpha_sub_ctype_fresh (CFun (_, V _, _)) = true
   145   | exists_alpha_sub_ctype_fresh (CFun (_, _, C2)) =
   146     exists_alpha_sub_ctype_fresh C2
   147   | exists_alpha_sub_ctype_fresh (CPair (C1, C2)) =
   148     exists exists_alpha_sub_ctype_fresh [C1, C2]
   149   | exists_alpha_sub_ctype_fresh (CType (_, Cs)) =
   150     exists exists_alpha_sub_ctype_fresh Cs
   151   | exists_alpha_sub_ctype_fresh (CRec _) = true
   152 
   153 (* string * typ list -> ctype list -> ctype *)
   154 fun constr_ctype_for_binders z Cs =
   155   fold_rev (fn C => curry3 CFun C (S Neg)) Cs (CRec z)
   156 
   157 (* ((string * typ list) * ctype) list -> ctype list -> ctype -> ctype *)
   158 fun repair_ctype _ _ CAlpha = CAlpha
   159   | repair_ctype cache seen (CFun (C1, a, C2)) =
   160     CFun (repair_ctype cache seen C1, a, repair_ctype cache seen C2)
   161   | repair_ctype cache seen (CPair Cp) =
   162     CPair (pairself (repair_ctype cache seen) Cp)
   163   | repair_ctype cache seen (CType (s, Cs)) =
   164     CType (s, maps (flatten_ctype o repair_ctype cache seen) Cs)
   165   | repair_ctype cache seen (CRec (z as (s, _))) =
   166     case AList.lookup (op =) cache z |> the of
   167       CRec _ => CType (s, [])
   168     | C => if member (op =) seen C then CType (s, [])
   169            else repair_ctype cache (C :: seen) C
   170 
   171 (* ((string * typ list) * ctype) list Unsynchronized.ref -> unit *)
   172 fun repair_datatype_cache cache =
   173   let
   174     (* (string * typ list) * ctype -> unit *)
   175     fun repair_one (z, C) =
   176       Unsynchronized.change cache
   177           (AList.update (op =) (z, repair_ctype (!cache) [] C))
   178   in List.app repair_one (rev (!cache)) end
   179 
   180 (* (typ * ctype) list -> (styp * ctype) list Unsynchronized.ref -> unit *)
   181 fun repair_constr_cache dtype_cache constr_cache =
   182   let
   183     (* styp * ctype -> unit *)
   184     fun repair_one (x, C) =
   185       Unsynchronized.change constr_cache
   186           (AList.update (op =) (x, repair_ctype dtype_cache [] C))
   187   in List.app repair_one (!constr_cache) end
   188 
   189 (* cdata -> typ -> ctype *)
   190 fun fresh_ctype_for_type ({ext_ctxt as {thy, ...}, alpha_T, max_fresh,
   191                            datatype_cache, constr_cache, ...} : cdata) =
   192   let
   193     (* typ -> typ -> ctype *)
   194     fun do_fun T1 T2 =
   195       let
   196         val C1 = do_type T1
   197         val C2 = do_type T2
   198         val a = if is_boolean_type (body_type T2) andalso
   199                    exists_alpha_sub_ctype_fresh C1 then
   200                   V (Unsynchronized.inc max_fresh)
   201                 else
   202                   S Neg
   203       in CFun (C1, a, C2) end
   204     (* typ -> ctype *)
   205     and do_type T =
   206       if T = alpha_T then
   207         CAlpha
   208       else case T of
   209         Type ("fun", [T1, T2]) => do_fun T1 T2
   210       | Type (@{type_name fun_box}, [T1, T2]) => do_fun T1 T2
   211       | Type ("*", [T1, T2]) => CPair (pairself do_type (T1, T2))
   212       | Type (z as (s, _)) =>
   213         if could_exist_alpha_sub_ctype thy alpha_T T then
   214           case AList.lookup (op =) (!datatype_cache) z of
   215             SOME C => C
   216           | NONE =>
   217             let
   218               val _ = Unsynchronized.change datatype_cache (cons (z, CRec z))
   219               val xs = datatype_constrs ext_ctxt T
   220               val (all_Cs, constr_Cs) =
   221                 fold_rev (fn (_, T') => fn (all_Cs, constr_Cs) =>
   222                              let
   223                                val binder_Cs = map do_type (binder_types T')
   224                                val new_Cs = filter exists_alpha_sub_ctype_fresh
   225                                                    binder_Cs
   226                                val constr_C = constr_ctype_for_binders z
   227                                                                        binder_Cs
   228                              in
   229                                (union (op =) new_Cs all_Cs,
   230                                 constr_C :: constr_Cs)
   231                              end)
   232                          xs ([], [])
   233               val C = CType (s, all_Cs)
   234               val _ = Unsynchronized.change datatype_cache
   235                           (AList.update (op =) (z, C))
   236               val _ = Unsynchronized.change constr_cache
   237                           (append (xs ~~ constr_Cs))
   238             in
   239               if forall (not o is_CRec o snd) (!datatype_cache) then
   240                 (repair_datatype_cache datatype_cache;
   241                  repair_constr_cache (!datatype_cache) constr_cache;
   242                  AList.lookup (op =) (!datatype_cache) z |> the)
   243               else
   244                 C
   245             end
   246         else
   247           CType (s, [])
   248       | _ => CType (Refute.string_of_typ T, [])
   249   in do_type end
   250 
   251 (* ctype -> ctype list *)
   252 fun prodC_factors (CPair (C1, C2)) = maps prodC_factors [C1, C2]
   253   | prodC_factors C = [C]
   254 (* ctype -> ctype list * ctype *)
   255 fun curried_strip_ctype (CFun (C1, S Neg, C2)) =
   256     curried_strip_ctype C2 |>> append (prodC_factors C1)
   257   | curried_strip_ctype C = ([], C)
   258 (* string -> ctype -> ctype *)
   259 fun sel_ctype_from_constr_ctype s C =
   260   let val (arg_Cs, dataC) = curried_strip_ctype C in
   261     CFun (dataC, S Neg,
   262           case sel_no_from_name s of ~1 => bool_C | n => nth arg_Cs n)
   263   end
   264 
   265 (* cdata -> styp -> ctype *)
   266 fun ctype_for_constr (cdata as {ext_ctxt as {thy, ...}, alpha_T, constr_cache,
   267                                 ...}) (x as (_, T)) =
   268   if could_exist_alpha_sub_ctype thy alpha_T T then
   269     case AList.lookup (op =) (!constr_cache) x of
   270       SOME C => C
   271     | NONE => (fresh_ctype_for_type cdata (body_type T);
   272                AList.lookup (op =) (!constr_cache) x |> the)
   273   else
   274     fresh_ctype_for_type cdata T
   275 fun ctype_for_sel (cdata as {ext_ctxt, ...}) (x as (s, _)) =
   276   x |> boxed_constr_for_sel ext_ctxt |> ctype_for_constr cdata
   277     |> sel_ctype_from_constr_ctype s
   278 
   279 (* literal list -> ctype -> ctype *)
   280 fun instantiate_ctype lits =
   281   let
   282     (* ctype -> ctype *)
   283     fun aux CAlpha = CAlpha
   284       | aux (CFun (C1, V x, C2)) =
   285         let
   286           val a = case AList.lookup (op =) lits x of
   287                     SOME sn => S sn
   288                   | NONE => V x
   289         in CFun (aux C1, a, aux C2) end
   290       | aux (CFun (C1, a, C2)) = CFun (aux C1, a, aux C2)
   291       | aux (CPair Cp) = CPair (pairself aux Cp)
   292       | aux (CType (s, Cs)) = CType (s, map aux Cs)
   293       | aux (CRec z) = CRec z
   294   in aux end
   295 
   296 datatype comp_op = Eq | Leq
   297 
   298 type comp = sign_atom * sign_atom * comp_op * var list
   299 type sign_expr = literal list
   300 
   301 datatype constraint_set =
   302   UnsolvableCSet |
   303   CSet of literal list * comp list * sign_expr list
   304 
   305 (* comp_op -> string *)
   306 fun string_for_comp_op Eq = "="
   307   | string_for_comp_op Leq = "\<le>"
   308 
   309 (* sign_expr -> string *)
   310 fun string_for_sign_expr [] = "\<bot>"
   311   | string_for_sign_expr lits =
   312     space_implode " \<or> " (map string_for_literal lits)
   313 
   314 (* constraint_set *)
   315 val slack = CSet ([], [], [])
   316 
   317 (* literal -> literal list option -> literal list option *)
   318 fun do_literal _ NONE = NONE
   319   | do_literal (x, sn) (SOME lits) =
   320     case AList.lookup (op =) lits x of
   321       SOME sn' => if sn = sn' then SOME lits else NONE
   322     | NONE => SOME ((x, sn) :: lits)
   323 
   324 (* comp_op -> var list -> sign_atom -> sign_atom -> literal list * comp list
   325    -> (literal list * comp list) option *)
   326 fun do_sign_atom_comp Eq [] a1 a2 (accum as (lits, comps)) =
   327     (case (a1, a2) of
   328        (S sn1, S sn2) => if sn1 = sn2 then SOME accum else NONE
   329      | (V x1, S sn2) =>
   330        Option.map (rpair comps) (do_literal (x1, sn2) (SOME lits))
   331      | (V _, V _) => SOME (lits, insert (op =) (a1, a2, Eq, []) comps)
   332      | _ => do_sign_atom_comp Eq [] a2 a1 accum)
   333   | do_sign_atom_comp Leq [] a1 a2 (accum as (lits, comps)) =
   334     (case (a1, a2) of
   335        (_, S Neg) => SOME accum
   336      | (S Pos, _) => SOME accum
   337      | (S Neg, S Pos) => NONE
   338      | (V _, V _) => SOME (lits, insert (op =) (a1, a2, Leq, []) comps)
   339      | _ => do_sign_atom_comp Eq [] a1 a2 accum)
   340   | do_sign_atom_comp cmp xs a1 a2 (accum as (lits, comps)) =
   341     SOME (lits, insert (op =) (a1, a2, cmp, xs) comps)
   342 
   343 (* comp -> var list -> ctype -> ctype -> (literal list * comp list) option
   344    -> (literal list * comp list) option *)
   345 fun do_ctype_comp _ _ _ _ NONE = NONE
   346   | do_ctype_comp _ _ CAlpha CAlpha accum = accum
   347   | do_ctype_comp Eq xs (CFun (C11, a1, C12)) (CFun (C21, a2, C22))
   348                   (SOME accum) =
   349      accum |> do_sign_atom_comp Eq xs a1 a2 |> do_ctype_comp Eq xs C11 C21
   350            |> do_ctype_comp Eq xs C12 C22
   351   | do_ctype_comp Leq xs (CFun (C11, a1, C12)) (CFun (C21, a2, C22))
   352                   (SOME accum) =
   353     (if exists_alpha_sub_ctype C11 then
   354        accum |> do_sign_atom_comp Leq xs a1 a2
   355              |> do_ctype_comp Leq xs C21 C11
   356              |> (case a2 of
   357                    S Neg => I
   358                  | S Pos => do_ctype_comp Leq xs C11 C21
   359                  | V x => do_ctype_comp Leq (x :: xs) C11 C21)
   360      else
   361        SOME accum)
   362     |> do_ctype_comp Leq xs C12 C22
   363   | do_ctype_comp cmp xs (C1 as CPair (C11, C12)) (C2 as CPair (C21, C22))
   364                   accum =
   365     (accum |> fold (uncurry (do_ctype_comp cmp xs)) [(C11, C21), (C12, C22)]
   366      handle Library.UnequalLengths =>
   367             raise CTYPE ("Nitpick_Mono.do_ctype_comp", [C1, C2]))
   368   | do_ctype_comp cmp xs (CType _) (CType _) accum =
   369     accum (* no need to compare them thanks to the cache *)
   370   | do_ctype_comp _ _ C1 C2 _ =
   371     raise CTYPE ("Nitpick_Mono.do_ctype_comp", [C1, C2])
   372 
   373 (* comp_op -> ctype -> ctype -> constraint_set -> constraint_set *)
   374 fun add_ctype_comp _ _ _ UnsolvableCSet = UnsolvableCSet
   375   | add_ctype_comp cmp C1 C2 (CSet (lits, comps, sexps)) =
   376     (print_g ("*** Add " ^ string_for_ctype C1 ^ " " ^ string_for_comp_op cmp ^
   377               " " ^ string_for_ctype C2);
   378      case do_ctype_comp cmp [] C1 C2 (SOME (lits, comps)) of
   379        NONE => (print_g "**** Unsolvable"; UnsolvableCSet)
   380      | SOME (lits, comps) => CSet (lits, comps, sexps))
   381 
   382 (* ctype -> ctype -> constraint_set -> constraint_set *)
   383 val add_ctypes_equal = add_ctype_comp Eq
   384 val add_is_sub_ctype = add_ctype_comp Leq
   385 
   386 (* sign -> sign_expr -> ctype -> (literal list * sign_expr list) option
   387    -> (literal list * sign_expr list) option *)
   388 fun do_notin_ctype_fv _ _ _ NONE = NONE
   389   | do_notin_ctype_fv Neg _ CAlpha accum = accum
   390   | do_notin_ctype_fv Pos [] CAlpha _ = NONE
   391   | do_notin_ctype_fv Pos [(x, sn)] CAlpha (SOME (lits, sexps)) =
   392     SOME lits |> do_literal (x, sn) |> Option.map (rpair sexps)
   393   | do_notin_ctype_fv Pos sexp CAlpha (SOME (lits, sexps)) =
   394     SOME (lits, insert (op =) sexp sexps)
   395   | do_notin_ctype_fv sn sexp (CFun (C1, S sn', C2)) accum =
   396     accum |> (if sn' = Pos andalso sn = Pos then do_notin_ctype_fv Pos sexp C1
   397               else I)
   398           |> (if sn' = Neg orelse sn = Pos then do_notin_ctype_fv Neg sexp C1
   399               else I)
   400           |> do_notin_ctype_fv sn sexp C2
   401   | do_notin_ctype_fv Pos sexp (CFun (C1, V x, C2)) accum =
   402     accum |> (case do_literal (x, Neg) (SOME sexp) of
   403                 NONE => I
   404               | SOME sexp' => do_notin_ctype_fv Pos sexp' C1)
   405           |> do_notin_ctype_fv Neg sexp C1
   406           |> do_notin_ctype_fv Pos sexp C2
   407   | do_notin_ctype_fv Neg sexp (CFun (C1, V x, C2)) accum =
   408     accum |> (case do_literal (x, Pos) (SOME sexp) of
   409                 NONE => I
   410               | SOME sexp' => do_notin_ctype_fv Pos sexp' C1)
   411           |> do_notin_ctype_fv Neg sexp C2
   412   | do_notin_ctype_fv sn sexp (CPair (C1, C2)) accum =
   413     accum |> fold (do_notin_ctype_fv sn sexp) [C1, C2]
   414   | do_notin_ctype_fv sn sexp (CType (_, Cs)) accum =
   415     accum |> fold (do_notin_ctype_fv sn sexp) Cs
   416   | do_notin_ctype_fv _ _ C _ =
   417     raise CTYPE ("Nitpick_Mono.do_notin_ctype_fv", [C])
   418 
   419 (* sign -> ctype -> constraint_set -> constraint_set *)
   420 fun add_notin_ctype_fv _ _ UnsolvableCSet = UnsolvableCSet
   421   | add_notin_ctype_fv sn C (CSet (lits, comps, sexps)) =
   422     (print_g ("*** Add " ^ string_for_ctype C ^ " is right-" ^
   423               (case sn of Neg => "unique" | Pos => "total") ^ ".");
   424      case do_notin_ctype_fv sn [] C (SOME (lits, sexps)) of
   425        NONE => (print_g "**** Unsolvable"; UnsolvableCSet)
   426      | SOME (lits, sexps) => CSet (lits, comps, sexps))
   427 
   428 (* ctype -> constraint_set -> constraint_set *)
   429 val add_ctype_is_right_unique = add_notin_ctype_fv Neg
   430 val add_ctype_is_right_total = add_notin_ctype_fv Pos
   431 
   432 (* constraint_set -> constraint_set -> constraint_set *)
   433 fun unite (CSet (lits1, comps1, sexps1)) (CSet (lits2, comps2, sexps2)) =
   434     (case SOME lits1 |> fold do_literal lits2 of
   435        NONE => (print_g "**** Unsolvable"; UnsolvableCSet)
   436      | SOME lits => CSet (lits, comps1 @ comps2, sexps1 @ sexps2))
   437   | unite _ _ = UnsolvableCSet
   438 
   439 (* sign -> bool *)
   440 fun bool_from_sign Pos = false
   441   | bool_from_sign Neg = true
   442 (* bool -> sign *)
   443 fun sign_from_bool false = Pos
   444   | sign_from_bool true = Neg
   445 
   446 (* literal -> PropLogic.prop_formula *)
   447 fun prop_for_literal (x, sn) =
   448   (not (bool_from_sign sn) ? PropLogic.Not) (PropLogic.BoolVar x)
   449 (* sign_atom -> PropLogic.prop_formula *)
   450 fun prop_for_sign_atom_eq (S sn', sn) =
   451     if sn = sn' then PropLogic.True else PropLogic.False
   452   | prop_for_sign_atom_eq (V x, sn) = prop_for_literal (x, sn)
   453 (* sign_expr -> PropLogic.prop_formula *)
   454 fun prop_for_sign_expr xs = PropLogic.exists (map prop_for_literal xs)
   455 (* var list -> sign -> PropLogic.prop_formula *)
   456 fun prop_for_exists_eq xs sn =
   457   PropLogic.exists (map (fn x => prop_for_literal (x, sn)) xs)
   458 (* comp -> PropLogic.prop_formula *)
   459 fun prop_for_comp (a1, a2, Eq, []) =
   460     PropLogic.SAnd (prop_for_comp (a1, a2, Leq, []),
   461                     prop_for_comp (a2, a1, Leq, []))
   462   | prop_for_comp (a1, a2, Leq, []) =
   463     PropLogic.SOr (prop_for_sign_atom_eq (a1, Pos),
   464                    prop_for_sign_atom_eq (a2, Neg))
   465   | prop_for_comp (a1, a2, cmp, xs) =
   466     PropLogic.SOr (prop_for_exists_eq xs Neg, prop_for_comp (a1, a2, cmp, []))
   467 
   468 (* var -> (int -> bool option) -> literal list -> literal list *)
   469 fun literals_from_assignments max_var assigns lits =
   470   fold (fn x => fn accum =>
   471            if AList.defined (op =) lits x then
   472              accum
   473            else case assigns x of
   474              SOME b => (x, sign_from_bool b) :: accum
   475            | NONE => accum) (max_var downto 1) lits
   476 
   477 (* literal list -> sign_atom -> sign option *)
   478 fun lookup_sign_atom _ (S sn) = SOME sn
   479   | lookup_sign_atom lit (V x) = AList.lookup (op =) lit x
   480 
   481 (* comp -> string *)
   482 fun string_for_comp (a1, a2, cmp, xs) =
   483   string_for_sign_atom a1 ^ " " ^ string_for_comp_op cmp ^
   484   subscript_string_for_vars " \<and> " xs ^ " " ^ string_for_sign_atom a2
   485 
   486 (* literal list -> comp list -> sign_expr list -> unit *)
   487 fun print_problem lits comps sexps =
   488   print_g ("*** Problem:\n" ^ cat_lines (map string_for_literal lits @
   489                                          map string_for_comp comps @
   490                                          map string_for_sign_expr sexps))
   491 
   492 (* literal list -> unit *)
   493 fun print_solution lits =
   494   let val (pos, neg) = List.partition (curry (op =) Pos o snd) lits in
   495     print_g ("*** Solution:\n" ^
   496              "+: " ^ commas (map (string_for_var o fst) pos) ^ "\n" ^
   497              "-: " ^ commas (map (string_for_var o fst) neg))
   498   end
   499 
   500 (* var -> constraint_set -> literal list list option *)
   501 fun solve _ UnsolvableCSet = (print_g "*** Problem: Unsolvable"; NONE)
   502   | solve max_var (CSet (lits, comps, sexps)) =
   503     let
   504       val _ = print_problem lits comps sexps
   505       val prop = PropLogic.all (map prop_for_literal lits @
   506                                 map prop_for_comp comps @
   507                                 map prop_for_sign_expr sexps)
   508       (* use the first ML solver (to avoid startup overhead) *)
   509       val solvers = !SatSolver.solvers
   510                     |> filter (member (op =) ["dptsat", "dpll"] o fst)
   511     in
   512       case snd (hd solvers) prop of
   513         SatSolver.SATISFIABLE assigns =>
   514         SOME (literals_from_assignments max_var assigns lits
   515               |> tap print_solution)
   516       | _ => NONE
   517     end
   518 
   519 (* var -> constraint_set -> bool *)
   520 val is_solvable = is_some oo solve
   521 
   522 type ctype_schema = ctype * constraint_set
   523 type ctype_context =
   524   {bounds: ctype list,
   525    frees: (styp * ctype) list,
   526    consts: (styp * ctype_schema) list}
   527 
   528 type accumulator = ctype_context * constraint_set
   529 
   530 val initial_gamma = {bounds = [], frees = [], consts = []}
   531 val unsolvable_accum = (initial_gamma, UnsolvableCSet)
   532 
   533 (* ctype -> ctype_context -> ctype_context *)
   534 fun push_bound C {bounds, frees, consts} =
   535   {bounds = C :: bounds, frees = frees, consts = consts}
   536 (* ctype_context -> ctype_context *)
   537 fun pop_bound {bounds, frees, consts} =
   538   {bounds = tl bounds, frees = frees, consts = consts}
   539   handle List.Empty => initial_gamma
   540 
   541 (* cdata -> term -> accumulator -> ctype * accumulator *)
   542 fun consider_term (cdata as {ext_ctxt as {ctxt, thy, def_table, ...}, alpha_T,
   543                              max_fresh, ...}) =
   544   let
   545     (* typ -> ctype *)
   546     val ctype_for = fresh_ctype_for_type cdata
   547     (* ctype -> ctype *)
   548     fun pos_set_ctype_for_dom C =
   549       CFun (C, S (if exists_alpha_sub_ctype C then Pos else Neg), bool_C)
   550     (* typ -> accumulator -> ctype * accumulator *)
   551     fun do_quantifier T (gamma, cset) =
   552       let
   553         val abs_C = ctype_for (domain_type (domain_type T))
   554         val body_C = ctype_for (range_type T)
   555       in
   556         (CFun (CFun (abs_C, S Neg, body_C), S Neg, body_C),
   557          (gamma, cset |> add_ctype_is_right_total abs_C))
   558       end
   559     fun do_equals T (gamma, cset) =
   560       let val C = ctype_for (domain_type T) in
   561         (CFun (C, S Neg, CFun (C, V (Unsynchronized.inc max_fresh),
   562                                ctype_for (nth_range_type 2 T))),
   563          (gamma, cset |> add_ctype_is_right_unique C))
   564       end
   565     fun do_robust_set_operation T (gamma, cset) =
   566       let
   567         val set_T = domain_type T
   568         val C1 = ctype_for set_T
   569         val C2 = ctype_for set_T
   570         val C3 = ctype_for set_T
   571       in
   572         (CFun (C1, S Neg, CFun (C2, S Neg, C3)),
   573          (gamma, cset |> add_is_sub_ctype C1 C3 |> add_is_sub_ctype C2 C3))
   574       end
   575     fun do_fragile_set_operation T (gamma, cset) =
   576       let
   577         val set_T = domain_type T
   578         val set_C = ctype_for set_T
   579         (* typ -> ctype *)
   580         fun custom_ctype_for (T as Type ("fun", [T1, T2])) =
   581             if T = set_T then set_C
   582             else CFun (custom_ctype_for T1, S Neg, custom_ctype_for T2)
   583           | custom_ctype_for T = ctype_for T
   584       in
   585         (custom_ctype_for T, (gamma, cset |> add_ctype_is_right_unique set_C))
   586       end
   587     (* typ -> accumulator -> ctype * accumulator *)
   588     fun do_pair_constr T accum =
   589       case ctype_for (nth_range_type 2 T) of
   590         C as CPair (a_C, b_C) =>
   591         (CFun (a_C, S Neg, CFun (b_C, S Neg, C)), accum)
   592       | C => raise CTYPE ("Nitpick_Mono.consider_term.do_pair_constr", [C])
   593     (* int -> typ -> accumulator -> ctype * accumulator *)
   594     fun do_nth_pair_sel n T =
   595       case ctype_for (domain_type T) of
   596         C as CPair (a_C, b_C) =>
   597         pair (CFun (C, S Neg, if n = 0 then a_C else b_C))
   598       | C => raise CTYPE ("Nitpick_Mono.consider_term.do_nth_pair_sel", [C])
   599     val unsolvable = (CType ("unsolvable", []), unsolvable_accum)
   600     (* typ -> term -> accumulator -> ctype * accumulator *)
   601     fun do_bounded_quantifier abs_T bound_t body_t accum =
   602       let
   603         val abs_C = ctype_for abs_T
   604         val (bound_C, accum) = accum |>> push_bound abs_C |> do_term bound_t
   605         val expected_bound_C = pos_set_ctype_for_dom abs_C
   606       in
   607         accum ||> add_ctypes_equal expected_bound_C bound_C |> do_term body_t
   608               ||> apfst pop_bound
   609       end
   610     (* term -> accumulator -> ctype * accumulator *)
   611     and do_term _ (_, UnsolvableCSet) = unsolvable
   612       | do_term t (accum as (gamma as {bounds, frees, consts}, cset)) =
   613         (case t of
   614            Const (x as (s, T)) =>
   615            (case AList.lookup (op =) consts x of
   616               SOME (C, cset') => (C, (gamma, cset |> unite cset'))
   617             | NONE =>
   618               if not (could_exist_alpha_subtype alpha_T T) then
   619                 (ctype_for T, accum)
   620               else case s of
   621                 @{const_name all} => do_quantifier T accum
   622               | @{const_name "=="} => do_equals T accum
   623               | @{const_name All} => do_quantifier T accum
   624               | @{const_name Ex} => do_quantifier T accum
   625               | @{const_name "op ="} => do_equals T accum
   626               | @{const_name The} => (print_g "*** The"; unsolvable)
   627               | @{const_name Eps} => (print_g "*** Eps"; unsolvable)
   628               | @{const_name If} =>
   629                 do_robust_set_operation (range_type T) accum
   630                 |>> curry3 CFun bool_C (S Neg)
   631               | @{const_name Pair} => do_pair_constr T accum
   632               | @{const_name fst} => do_nth_pair_sel 0 T accum
   633               | @{const_name snd} => do_nth_pair_sel 1 T accum 
   634               | @{const_name Id} =>
   635                 (CFun (ctype_for (domain_type T), S Neg, bool_C), accum)
   636               | @{const_name insert} =>
   637                 let
   638                   val set_T = domain_type (range_type T)
   639                   val C1 = ctype_for (domain_type set_T)
   640                   val C1' = pos_set_ctype_for_dom C1
   641                   val C2 = ctype_for set_T
   642                   val C3 = ctype_for set_T
   643                 in
   644                   (CFun (C1, S Neg, CFun (C2, S Neg, C3)),
   645                    (gamma, cset |> add_ctype_is_right_unique C1
   646                                 |> add_is_sub_ctype C1' C3
   647                                 |> add_is_sub_ctype C2 C3))
   648                 end
   649               | @{const_name converse} =>
   650                 let
   651                   val x = Unsynchronized.inc max_fresh
   652                   (* typ -> ctype *)
   653                   fun ctype_for_set T =
   654                     CFun (ctype_for (domain_type T), V x, bool_C)
   655                   val ab_set_C = domain_type T |> ctype_for_set
   656                   val ba_set_C = range_type T |> ctype_for_set
   657                 in (CFun (ab_set_C, S Neg, ba_set_C), accum) end
   658               | @{const_name trancl} => do_fragile_set_operation T accum
   659               | @{const_name rtrancl} => (print_g "*** rtrancl"; unsolvable)
   660               | @{const_name lower_semilattice_fun_inst.inf_fun} =>
   661                 do_robust_set_operation T accum
   662               | @{const_name upper_semilattice_fun_inst.sup_fun} =>
   663                 do_robust_set_operation T accum
   664               | @{const_name finite} =>
   665                 let val C1 = ctype_for (domain_type (domain_type T)) in
   666                   (CFun (pos_set_ctype_for_dom C1, S Neg, bool_C), accum)
   667                 end
   668               | @{const_name rel_comp} =>
   669                 let
   670                   val x = Unsynchronized.inc max_fresh
   671                   (* typ -> ctype *)
   672                   fun ctype_for_set T =
   673                     CFun (ctype_for (domain_type T), V x, bool_C)
   674                   val bc_set_C = domain_type T |> ctype_for_set
   675                   val ab_set_C = domain_type (range_type T) |> ctype_for_set
   676                   val ac_set_C = nth_range_type 2 T |> ctype_for_set
   677                 in
   678                   (CFun (bc_set_C, S Neg, CFun (ab_set_C, S Neg, ac_set_C)),
   679                    accum)
   680                 end
   681               | @{const_name image} =>
   682                 let
   683                   val a_C = ctype_for (domain_type (domain_type T))
   684                   val b_C = ctype_for (range_type (domain_type T))
   685                 in
   686                   (CFun (CFun (a_C, S Neg, b_C), S Neg,
   687                          CFun (pos_set_ctype_for_dom a_C, S Neg,
   688                                pos_set_ctype_for_dom b_C)), accum)
   689                 end
   690               | @{const_name Sigma} =>
   691                 let
   692                   val x = Unsynchronized.inc max_fresh
   693                   (* typ -> ctype *)
   694                   fun ctype_for_set T =
   695                     CFun (ctype_for (domain_type T), V x, bool_C)
   696                   val a_set_T = domain_type T
   697                   val a_C = ctype_for (domain_type a_set_T)
   698                   val b_set_C = ctype_for_set (range_type (domain_type
   699                                                                (range_type T)))
   700                   val a_set_C = ctype_for_set a_set_T
   701                   val a_to_b_set_C = CFun (a_C, S Neg, b_set_C)
   702                   val ab_set_C = ctype_for_set (nth_range_type 2 T)
   703                 in
   704                   (CFun (a_set_C, S Neg, CFun (a_to_b_set_C, S Neg, ab_set_C)),
   705                    accum)
   706                 end
   707               | @{const_name minus_fun_inst.minus_fun} =>
   708                 let
   709                   val set_T = domain_type T
   710                   val left_set_C = ctype_for set_T
   711                   val right_set_C = ctype_for set_T
   712                 in
   713                   (CFun (left_set_C, S Neg,
   714                          CFun (right_set_C, S Neg, left_set_C)),
   715                    (gamma, cset |> add_ctype_is_right_unique right_set_C
   716                                 |> add_is_sub_ctype right_set_C left_set_C))
   717                 end
   718               | @{const_name ord_fun_inst.less_eq_fun} =>
   719                 do_fragile_set_operation T accum
   720               | @{const_name Tha} =>
   721                 let
   722                   val a_C = ctype_for (domain_type (domain_type T))
   723                   val a_set_C = pos_set_ctype_for_dom a_C
   724                 in (CFun (a_set_C, S Neg, a_C), accum) end
   725               | @{const_name FunBox} =>
   726                 let val dom_C = ctype_for (domain_type T) in
   727                   (CFun (dom_C, S Neg, dom_C), accum)
   728                 end
   729               | _ => if is_sel s then
   730                        if constr_name_for_sel_like s = @{const_name FunBox} then
   731                          let val dom_C = ctype_for (domain_type T) in
   732                            (CFun (dom_C, S Neg, dom_C), accum)
   733                          end
   734                        else
   735                          (ctype_for_sel cdata x, accum)
   736                      else if is_constr thy x then
   737                        (ctype_for_constr cdata x, accum)
   738                      else if is_built_in_const true x then
   739                        case def_of_const thy def_table x of
   740                          SOME t' => do_term t' accum
   741                        | NONE => (print_g ("*** built-in " ^ s); unsolvable)
   742                      else
   743                        (ctype_for T, accum))
   744          | Free (x as (_, T)) =>
   745            (case AList.lookup (op =) frees x of
   746               SOME C => (C, accum)
   747             | NONE =>
   748               let val C = ctype_for T in
   749                 (C, ({bounds = bounds, frees = (x, C) :: frees,
   750                       consts = consts}, cset))
   751               end)
   752          | Var _ => (print_g "*** Var"; unsolvable)
   753          | Bound j => (nth bounds j, accum)
   754          | Abs (_, T, @{const False}) => (ctype_for (T --> bool_T), accum)
   755          | Abs (s, T, t') =>
   756            let
   757              val C = ctype_for T
   758              val (C', accum) = do_term t' (accum |>> push_bound C)
   759            in (CFun (C, S Neg, C'), accum |>> pop_bound) end
   760          | Const (@{const_name All}, _)
   761            $ Abs (_, T', @{const "op -->"} $ (t1 $ Bound 0) $ t2) =>
   762            do_bounded_quantifier T' t1 t2 accum
   763          | Const (@{const_name Ex}, _)
   764            $ Abs (_, T', @{const "op &"} $ (t1 $ Bound 0) $ t2) =>
   765            do_bounded_quantifier T' t1 t2 accum
   766          | Const (@{const_name Let}, _) $ t1 $ t2 =>
   767            do_term (betapply (t2, t1)) accum
   768          | t1 $ t2 =>
   769            let
   770              val (C1, accum) = do_term t1 accum
   771              val (C2, accum) = do_term t2 accum
   772            in
   773              case accum of
   774                (_, UnsolvableCSet) => unsolvable
   775              | _ => case C1 of
   776                       CFun (C11, _, C12) =>
   777                       (C12, accum ||> add_is_sub_ctype C2 C11)
   778                     | _ => raise CTYPE ("Nitpick_Mono.consider_term.do_term \
   779                                         \(op $)", [C1])
   780            end)
   781         |> tap (fn (C, _) =>
   782                    print_g ("  \<Gamma> \<turnstile> " ^
   783                             Syntax.string_of_term ctxt t ^ " : " ^
   784                             string_for_ctype C))
   785   in do_term end
   786 
   787 (* cdata -> sign -> term -> accumulator -> accumulator *)
   788 fun consider_general_formula (cdata as {ext_ctxt as {ctxt, ...}, ...}) =
   789   let
   790     (* typ -> ctype *)
   791     val ctype_for = fresh_ctype_for_type cdata
   792     (* term -> accumulator -> ctype * accumulator *)
   793     val do_term = consider_term cdata
   794     (* sign -> term -> accumulator -> accumulator *)
   795     fun do_formula _ _ (_, UnsolvableCSet) = unsolvable_accum
   796       | do_formula sn t (accum as (gamma as {bounds, frees, consts}, cset)) =
   797         let
   798           (* term -> accumulator -> accumulator *)
   799           val do_co_formula = do_formula sn
   800           val do_contra_formula = do_formula (negate sn)
   801           (* string -> typ -> term -> accumulator *)
   802           fun do_quantifier quant_s abs_T body_t =
   803             let
   804               val abs_C = ctype_for abs_T
   805               val side_cond = ((sn = Neg) = (quant_s = @{const_name Ex}))
   806               val cset = cset |> side_cond ? add_ctype_is_right_total abs_C
   807             in
   808               (gamma |> push_bound abs_C, cset) |> do_co_formula body_t
   809                                                 |>> pop_bound
   810             end
   811           (* typ -> term -> accumulator *)
   812           fun do_bounded_quantifier abs_T body_t =
   813             accum |>> push_bound (ctype_for abs_T) |> do_co_formula body_t
   814                   |>> pop_bound
   815           (* term -> term -> accumulator *)
   816           fun do_equals t1 t2 =
   817             case sn of
   818               Pos => do_term t accum |> snd
   819             | Neg => let
   820                        val (C1, accum) = do_term t1 accum
   821                        val (C2, accum) = do_term t2 accum
   822                      in accum ||> add_ctypes_equal C1 C2 end
   823         in
   824           case t of
   825             Const (s0 as @{const_name all}, _) $ Abs (_, T1, t1) =>
   826             do_quantifier s0 T1 t1
   827           | Const (@{const_name "=="}, _) $ t1 $ t2 => do_equals t1 t2
   828           | @{const "==>"} $ t1 $ t2 =>
   829             accum |> do_contra_formula t1 |> do_co_formula t2
   830           | @{const Trueprop} $ t1 => do_co_formula t1 accum
   831           | @{const Not} $ t1 => do_contra_formula t1 accum
   832           | Const (@{const_name All}, _)
   833             $ Abs (_, T1, t1 as @{const "op -->"} $ (_ $ Bound 0) $ _) =>
   834             do_bounded_quantifier T1 t1
   835           | Const (s0 as @{const_name All}, _) $ Abs (_, T1, t1) =>
   836             do_quantifier s0 T1 t1
   837           | Const (@{const_name Ex}, _)
   838             $ Abs (_, T1, t1 as @{const "op &"} $ (_ $ Bound 0) $ _) =>
   839             do_bounded_quantifier T1 t1
   840           | Const (s0 as @{const_name Ex}, _) $ Abs (_, T1, t1) =>
   841             do_quantifier s0 T1 t1
   842           | Const (@{const_name "op ="}, _) $ t1 $ t2 => do_equals t1 t2
   843           | @{const "op &"} $ t1 $ t2 =>
   844             accum |> do_co_formula t1 |> do_co_formula t2
   845           | @{const "op |"} $ t1 $ t2 =>
   846             accum |> do_co_formula t1 |> do_co_formula t2
   847           | @{const "op -->"} $ t1 $ t2 =>
   848             accum |> do_contra_formula t1 |> do_co_formula t2
   849           | Const (@{const_name If}, _) $ t1 $ t2 $ t3 =>
   850             accum |> do_term t1 |> snd |> fold do_co_formula [t2, t3]
   851           | Const (@{const_name Let}, _) $ t1 $ t2 =>
   852             do_co_formula (betapply (t2, t1)) accum
   853           | _ => do_term t accum |> snd
   854         end
   855         |> tap (fn _ => print_g ("\<Gamma> \<turnstile> " ^
   856                                  Syntax.string_of_term ctxt t ^
   857                                  " : o\<^sup>" ^ string_for_sign sn))
   858   in do_formula end
   859 
   860 (* The harmless axiom optimization below is somewhat too aggressive in the face
   861    of (rather peculiar) user-defined axioms. *)
   862 val harmless_consts =
   863   [@{const_name ord_class.less}, @{const_name ord_class.less_eq}]
   864 val bounteous_consts = [@{const_name bisim}]
   865 
   866 (* term -> bool *)
   867 fun is_harmless_axiom t =
   868   Term.add_consts t [] |> filter_out (is_built_in_const true)
   869   |> (forall (member (op =) harmless_consts o original_name o fst)
   870       orf exists (member (op =) bounteous_consts o fst))
   871 
   872 (* cdata -> sign -> term -> accumulator -> accumulator *)
   873 fun consider_nondefinitional_axiom cdata sn t =
   874   not (is_harmless_axiom t) ? consider_general_formula cdata sn t
   875 
   876 (* cdata -> term -> accumulator -> accumulator *)
   877 fun consider_definitional_axiom (cdata as {ext_ctxt as {thy, ...}, ...}) t =
   878   if not (is_constr_pattern_formula thy t) then
   879     consider_nondefinitional_axiom cdata Pos t
   880   else if is_harmless_axiom t then
   881     I
   882   else
   883     let
   884       (* term -> accumulator -> ctype * accumulator *)
   885       val do_term = consider_term cdata
   886       (* typ -> term -> accumulator -> accumulator *)
   887       fun do_all abs_T body_t accum =
   888         let val abs_C = fresh_ctype_for_type cdata abs_T in
   889           accum |>> push_bound abs_C |> do_formula body_t |>> pop_bound
   890         end
   891       (* term -> term -> accumulator -> accumulator *)
   892       and do_implies t1 t2 = do_term t1 #> snd #> do_formula t2
   893       and do_equals t1 t2 accum =
   894         let
   895           val (C1, accum) = do_term t1 accum
   896           val (C2, accum) = do_term t2 accum
   897         in accum ||> add_ctypes_equal C1 C2 end
   898       (* term -> accumulator -> accumulator *)
   899       and do_formula _ (_, UnsolvableCSet) = unsolvable_accum
   900         | do_formula t accum =
   901           case t of
   902             Const (@{const_name all}, _) $ Abs (_, T1, t1) => do_all T1 t1 accum
   903           | @{const Trueprop} $ t1 => do_formula t1 accum
   904           | Const (@{const_name "=="}, _) $ t1 $ t2 => do_equals t1 t2 accum
   905           | @{const "==>"} $ t1 $ t2 => do_implies t1 t2 accum
   906           | @{const Pure.conjunction} $ t1 $ t2 =>
   907             accum |> do_formula t1 |> do_formula t2
   908           | Const (@{const_name All}, _) $ Abs (_, T1, t1) => do_all T1 t1 accum
   909           | Const (@{const_name "op ="}, _) $ t1 $ t2 => do_equals t1 t2 accum
   910           | @{const "op &"} $ t1 $ t2 => accum |> do_formula t1 |> do_formula t2
   911           | @{const "op -->"} $ t1 $ t2 => do_implies t1 t2 accum
   912           | _ => raise TERM ("Nitpick_Mono.consider_definitional_axiom.\
   913                              \do_formula", [t])
   914     in do_formula t end
   915 
   916 (* Proof.context -> literal list -> term -> ctype -> string *)
   917 fun string_for_ctype_of_term ctxt lits t C =
   918   Syntax.string_of_term ctxt t ^ " : " ^
   919   string_for_ctype (instantiate_ctype lits C)
   920 
   921 (* theory -> literal list -> ctype_context -> unit *)
   922 fun print_ctype_context ctxt lits ({frees, consts, ...} : ctype_context) =
   923   map (fn (x, C) => string_for_ctype_of_term ctxt lits (Free x) C) frees @
   924   map (fn (x, (C, _)) => string_for_ctype_of_term ctxt lits (Const x) C) consts
   925   |> cat_lines |> print_g
   926 
   927 (* extended_context -> typ -> term list -> term list -> term -> bool *)
   928 fun formulas_monotonic (ext_ctxt as {ctxt, ...}) alpha_T def_ts nondef_ts
   929                        core_t =
   930   let
   931     val _ = print_g ("****** " ^ string_for_ctype CAlpha ^ " is " ^
   932                      Syntax.string_of_typ ctxt alpha_T)
   933     val cdata as {max_fresh, ...} = initial_cdata ext_ctxt alpha_T
   934     val (gamma, cset) =
   935       (initial_gamma, slack)
   936       |> fold (consider_definitional_axiom cdata) def_ts
   937       |> fold (consider_nondefinitional_axiom cdata Pos) nondef_ts
   938       |> consider_general_formula cdata Pos core_t
   939   in
   940     case solve (!max_fresh) cset of
   941       SOME lits => (print_ctype_context ctxt lits gamma; true)
   942     | _ => false
   943   end
   944   handle CTYPE (loc, Cs) => raise BAD (loc, commas (map string_for_ctype Cs))
   945 
   946 end;