1(* ---------------------------------------------------------------------- 2 Proves theorems about record types. A record type is set up by first 3 calling standard datatype code to set up a new type with one 4 constructor and as many arguments to that constructor as there are 5 fields in the desired record type, and with the corresponding types. 6 7 The main function takes this new type's tyinfo data, as well as a 8 list of the field names. 9 10 Author: Michael Norrish 11 ---------------------------------------------------------------------- *) 12 13structure RecordType :> RecordType = 14struct 15 16open HolKernel Parse boolLib 17 18structure Parse = struct 19 open Parse 20 val (Type,Term) = parse_from_grammars boolTheory.bool_grammars 21end 22open Parse 23 24val K_tm = combinSyntax.K_tm 25 26 27val ERR = mk_HOL_ERR "RecordType"; 28fun mk_recordtype_constructor s = "recordtype." ^ s 29 30(* ---------------------------------------------------------------------- 31 General utilities 32 ---------------------------------------------------------------------- *) 33 34fun map3 f ([], _, _) = [] 35 | map3 f (x::xs, ys, zs) = f (x, hd ys, hd zs) :: map3 f (xs, tl ys, tl zs) 36 37fun insert n e l = 38 if n < 1 then raise Fail "Bad position to insert at" else 39 if n = 1 then e::l else (hd l)::(insert (n-1) e (tl l)); 40fun delete n l = 41 if n < 1 then raise Fail "Bad position to delete at" else 42 if n = 1 then tl l 43 else (hd l)::(delete (n-1) (tl l)); 44fun update n e = (insert n e) o (delete n); 45fun findi e [] = raise Fail "Couldn't find element" 46 | findi e (x::xs) = if e = x then 1 else 1 + findi e xs; 47fun foldr f zero [] = zero 48 | foldr f zero (x::xs) = f x (foldr f zero xs) 49fun foldl f zero [] = zero 50 | foldl f zero (x::xs) = foldl f (f zero x) xs 51 52fun dest_all_type ty = 53 dest_type ty handle HOL_ERR _ => (dest_vartype ty, []) 54 55fun variant tml tm = let 56 fun name_of tm = if is_var tm then SOME (fst(dest_var tm)) else NONE 57 val avoidstrs = List.mapPartial name_of tml 58 val (Name, Ty) = Term.dest_var tm 59in 60 Term.mk_var(Lexis.gen_variant Lexis.tmvar_vary avoidstrs Name,Ty) 61end 62 63 64(* app_letter = "appropriate letter" *) 65fun app_letter ty = 66 if is_vartype ty then String.substring(dest_vartype ty, 1, 1) 67 else String.substring(#Tyop (dest_thy_type ty), 0, 1) 68 69(* given two lists of equal length n, produce a list of length *) 70(* n(n-1) where each element of the first list is paired with *) 71(* each of the second, except the one that corresponds to it *) 72local 73 fun nrecfilter fnc [] n = [] 74 | nrecfilter fnc (hd::tl) n = 75 if not (fnc (n,hd)) then 76 nrecfilter fnc tl (n+1) 77 else 78 hd::nrecfilter fnc tl (n+1) 79in 80fun nfilter fnc l = nrecfilter fnc l 1 81end 82 83fun crossprod l1 l2 = 84 let 85 fun pairer x y = x @ map (fn item => (y,item)) l2 in 86 foldl pairer [] l1 87 end 88 89fun crosslessdiag l1 l2 = 90 let 91 val cross = crossprod l1 l2 and 92 diaglength = List.length l1 + 1 in 93 nfilter (fn (n,_) => not (n mod diaglength = 1)) cross 94 end 95 96fun update_tyinfo opt new_simpls tyinfo = 97 let open TypeBasePure 98 val existing_simpls = simpls_of tyinfo 99 fun add_rwts {convs,rewrs} newrwts = {convs=convs, rewrs=rewrs @ newrwts} 100 val base = put_simpls (add_rwts existing_simpls new_simpls) tyinfo 101 in 102 case opt of 103 NONE => base 104 | SOME (flds,accs,upds) => 105 put_accessors accs 106 (put_updates upds 107 (put_fields flds base)) 108end 109 110fun digit_suffix s = 111 let 112 val ss = Substring.full s 113 val (l,r) = Substring.splitr Char.isDigit ss 114 in 115 (Substring.string l, Int.fromString (Substring.string r)) 116 end 117 118fun nexttyvar ty = 119 let 120 val qnm = dest_vartype ty 121 val nm = String.extract(qnm, 1, NONE) 122 in 123 if size nm = 1 andalso Char.isLower (String.sub(nm, 0)) then 124 if nm <> "z" then 125 mk_vartype("'" ^ String.str (Char.chr(Char.ord (String.sub(nm,0)) + 1))) 126 else 127 mk_vartype "'a0" 128 else 129 case digit_suffix qnm of 130 (pfx, NONE) => mk_vartype (pfx ^ "0") 131 | (pfx, SOME i) => mk_vartype (pfx ^ Int.toString (i + 1)) 132 end 133 134fun tyvariant avoids ty = 135 if mem ty avoids then tyvariant avoids (nexttyvar ty) 136 else ty 137 138(* assumes that avoids is a superset of tyvs *) 139fun freshsubst avoids tyvs = 140 let 141 fun foldthis (tyv, (avoids, s)) = 142 let 143 val v' = tyvariant avoids tyv 144 in 145 (v'::avoids, (tyv |-> v') :: s) 146 end 147 in 148 #2 (List.foldl foldthis (avoids, []) tyvs) 149 end 150 151 152(* ---------------------------------------------------------------------- 153 prove_recordtype_thms 154 155 Where all the work happens. The following function is huge and 156 revolting. 157 ---------------------------------------------------------------------- *) 158 159fun prove_recordtype_thms (tyinfo, fields) = let 160 161 val save_thm = Feedback.trace ("Theory.save_thm_reporting", 0) save_thm 162 fun store_thm (n, t, tac) = save_thm(n, prove(t,tac)) 163 164 val app2 = C (curry op^) 165 val typthm = TypeBasePure.axiom_of tyinfo 166 val (thyname,typename) = TypeBasePure.ty_name_of tyinfo 167 val constructor = 168 case TypeBasePure.constructors_of tyinfo of 169 [x] => x 170 | _ => raise ERR "prove_recordtype_thms" 171 "Type to be record has more than one constructor" 172 val (typ, types) = let 173 fun domtys acc ty = let 174 val (d1, rty) = dom_rng ty 175 in 176 domtys (d1::acc) rty 177 end handle HOL_ERR _ => (ty, List.rev acc) 178 in 179 domtys [] (type_of constructor) 180 end 181 val varying_tyvs = let 182 val tymap = Binarymap.mkDict Type.compare : (hol_type,int) Binarymap.dict 183 fun recurse m tys = 184 case tys of 185 [] => m 186 | ty::tyrest => 187 let 188 val tyvs = HOLset.fromList Type.compare (Type.type_vars ty) 189 fun foldthis (tyv,m) = 190 case Binarymap.peek(m, tyv) of 191 NONE => Binarymap.insert(m,tyv,1) 192 | SOME i => Binarymap.insert(m,tyv,i+1) 193 in 194 recurse (HOLset.foldl foldthis m tyvs) tyrest 195 end 196 in 197 Binarymap.foldl (fn (tyv,c,acc) => if c = 1 then tyv::acc else acc) 198 [] 199 (recurse tymap types) 200 end 201 202 val tysigma = let 203 val avoids = Type.type_varsl types 204 in 205 freshsubst avoids varying_tyvs 206 end 207 val sigsubst = type_subst tysigma 208 val var = Psyntax.mk_var(app_letter typ, typ) 209 val size = length fields 210 211 val _ = length types = length fields orelse 212 raise HOL_ERR {origin_function = "prove_recordtype_thms", 213 origin_structure = "RecordType", 214 message = 215 "Number of fields doesn't match number of types"} 216 217 (* we now have the type actually defined in typthm *) 218 fun letgen x y = x @ [variant x (mk_var (app_letter y,y))] 219 val typeletters = foldl letgen [] types 220 221 (* now generate accessor functions *) 222 val accfn_types = map (fn x => (typ --> x)) types 223 local 224 fun constructor_args [] = map boolSyntax.mk_arb types 225 | constructor_args ((f,t)::xs) = let 226 val rest = constructor_args xs 227 val posn = findi f fields handle _ => 228 raise Fail "Bad field name" 229 in 230 update posn t rest 231 end 232 in 233 fun create_term ftl = 234 list_mk_comb(constructor, constructor_args ftl) 235 end 236 val cons_comb = list_mk_comb(constructor, typeletters) 237 val access_fn_names = map (fn n => typename^"_"^n) fields 238 val access_defn_terms = 239 map3 (fn (afn_name, typeletter, accfn_type) => 240 mk_eq(mk_comb(mk_var(afn_name, accfn_type), 241 cons_comb), 242 typeletter)) 243 (access_fn_names, typeletters, accfn_types) 244 val access_defns = 245 ListPair.map 246 (fn (name, tm) => Prim_rec.new_recursive_definition 247 {def = tm, name = name, rec_axiom = typthm}) 248 (access_fn_names, access_defn_terms) 249 val accessor_thm = 250 save_thm(typename^"_accessors", LIST_CONJ access_defns) 251 fun mk_const(n,ty) = mk_thy_const{Thy=current_theory(), Name = n, Ty = ty} 252 val accfn_terms = ListPair.map mk_const (access_fn_names, accfn_types) 253 254 (* generate functional update functions *) 255 (* these are of the form : 256 field_fupd f o = field_update (f (field o)) o 257 *) 258 val fupd_names = map (fn s => s ^ "_fupd") access_fn_names 259 fun getredex t = let 260 val tyvs = type_vars t 261 in 262 List.filter (fn {redex,residue} => mem redex tyvs) 263 end 264 val fupd_fun_types = 265 map (fn t => (getredex t tysigma, t --> sigsubst t)) types 266 val fupd_types = 267 map (fn (s,t) => (s, t --> typ --> type_subst s typ)) fupd_fun_types 268 val fupd_terms = 269 ListPair.map (fn (n,(s,ty)) => (s, mk_var(n,ty))) (fupd_names, fupd_types) 270 fun mk_fupd_defn ((s, fldfupd), result, (pos, acc)) = let 271 val (f_ty, _) = dom_rng (type_of fldfupd) 272 val f0 = mk_var("f", f_ty) 273 val f = variant typeletters f0 274 in 275 (pos + 1, 276 mk_eq(list_mk_comb(fldfupd, [f, cons_comb]), 277 list_mk_comb(Term.inst s constructor, 278 update pos (mk_comb(f, result)) typeletters)) :: acc) 279 end 280 val (_, fupd_def_terms0) = ListPair.foldl mk_fupd_defn (1, []) 281 (fupd_terms, typeletters) 282 val fupd_def_terms = List.rev fupd_def_terms0 283 fun mk_defn_th (n, t) = 284 new_recursive_definition {def = t, name = n, rec_axiom = typthm} 285 val fupdfn_thms = ListPair.map mk_defn_th (fupd_names, fupd_def_terms) 286 val fupdfn_thm = 287 save_thm(typename^"_fn_updates", LIST_CONJ fupdfn_thms) 288 val fupdfn_terms = 289 map (fn (s, v) => (s, mk_const (dest_var v))) fupd_terms 290 291 292 (* do cases and induction theorem *) 293 val induction_thm = TypeBasePure.induction_of tyinfo 294 val cases_thm = TypeBasePure.nchotomy_of tyinfo 295 296 fun gen_var_domty(name, tm, avoids) = let 297 val v0 = mk_var(name, #1 (dom_rng (type_of tm))) 298 in 299 variant avoids v0 300 end 301 302 (* do acc of fupdates theorems *) 303 (* i.e. thms of the form 304 (r with fld1 updated by val).fld2 = r.fld2 305 ( == 306 fld1 (fld2_fupd val r) = fld1 r 307 ) 308 *) 309 fun create_goal (acc, (s, fupd)) = let 310 val f = gen_var_domty("f", fupd, [var]) 311 in 312 Term`^(Term.inst s acc) (^fupd ^f ^var) = ^acc ^var` 313 end 314 val combinations = crosslessdiag accfn_terms fupdfn_terms 315 val goals = map create_goal combinations 316 fun create_goal (acc, (s, fupd)) = let 317 val f = gen_var_domty("f", fupd, [var]) 318 in 319 Term`^(Term.inst s acc) (^fupd ^f ^var) = ^f (^acc ^var)` 320 end 321 val diag_goals = ListPair.map create_goal (accfn_terms, fupdfn_terms) 322 val tactic = STRUCT_CASES_TAC (SPEC var cases_thm) THEN 323 REWRITE_TAC [accessor_thm, fupdfn_thm, combinTheory.o_THM] THEN 324 BETA_TAC THEN REWRITE_TAC [] 325 val thms = map (C (curry prove) tactic) (goals @ diag_goals) 326 val accfupd_thm = 327 save_thm(typename^"_accfupds", LIST_CONJ (map GEN_ALL thms)) 328 329 fun to_composition t = let 330 val (f, gx) = dest_comb t 331 in 332 if is_comb gx then let 333 val (g, x) = dest_comb gx 334 in 335 SYM (ISPECL [f, g, x] combinTheory.o_THM) 336 end 337 else REFL t 338 end 339 fun o_assoc_munge th = let 340 (* th of form f o g = x; want to produce f o (g o h) = x o h *) 341 val (l, r) = dest_eq (concl th) 342 val l_ty = type_of l 343 val (dom, rng) = dom_rng l_ty 344 val tyvs = map dest_vartype (type_vars_in_term l) 345 val newtyv = mk_vartype(Lexis.gen_variant Lexis.tyvar_vary tyvs "'a") 346 val h = mk_var("h", newtyv --> dom) 347 val new_o = mk_thy_const{Name = "o", Thy = "combin", 348 Ty = l_ty --> (type_of h --> (newtyv --> rng))} 349 val newth = AP_THM (AP_TERM new_o th) h 350 in 351 REWRITE_RULE [GSYM combinTheory.o_ASSOC] newth 352 end 353 354 fun munge_to_composition thm = let 355 val thm = SPEC_ALL thm 356 val (l, r) = dest_eq (concl thm) 357 val lthm = SYM (to_composition l) 358 val rthm = to_composition r 359 val new_eq = TRANS (TRANS lthm thm) rthm 360 val gnew_eq = EXT (GEN (rand (rand (concl new_eq))) new_eq) 361 val o_assoc_version = o_assoc_munge gnew_eq 362 in 363 CONJ (GEN_ALL gnew_eq) (GEN_ALL o_assoc_version) 364 end 365 366 (* do fupdates of (same) fupdates *) 367 (* i.e., fupd_fld1 f (fupd_fld1 g r) = fupd_fld1 (f o g) r *) 368 fun create_goal (s, fupd) = let 369 val fupdty = type_of fupd 370 val (gty,r) = dom_rng fupdty 371 val (gd, gr) = dom_rng gty 372 val ftys = freshsubst (type_vars fupdty) (map #residue s) 373 val fty = gr --> type_subst ftys gr 374 val f = variant [var] (mk_var("f", fty)) 375 val g = variant [var, f] (mk_var("g", gty)) 376 in 377 mk_eq(list_mk_comb(inst s (inst ftys fupd), 378 [f, list_mk_comb(fupd, [g, var])]), 379 list_mk_comb(inst ftys fupd, [combinSyntax.mk_o(f, g), var])) 380 end 381 val goals = map create_goal fupdfn_terms 382 val thms = map (C (curry prove) tactic) goals 383 val fupdfupd_thm = 384 save_thm(typename^"_fupdfupds", LIST_CONJ (map GEN_ALL thms)) 385 val fupdfupds_comp_thm = 386 save_thm(typename^"_fupdfupds_comp", 387 LIST_CONJ (map munge_to_composition thms)) 388 389 (* do fupdates of (different) fupdates *) 390 val combinations = crossprod fupdfn_terms fupdfn_terms 391 val filterfn = (fn (n,_) => let val m = n - 1 392 val d = m div size 393 val m = m - (d * size) in 394 d > m end) 395 val lower_triangle = nfilter filterfn combinations 396 fun create_goal((s1, f1),(s2, f2)) = let 397 val (f_t, _) = dom_rng (type_of f1) 398 val (g_t, _) = dom_rng (type_of f2) 399 val f = variant [var] (mk_var("f", f_t)) 400 val g = variant [var, f] (mk_var("g", g_t)) 401 in 402 mk_eq(list_mk_comb(inst s2 f1, [f, list_mk_comb(f2, [g, var])]), 403 list_mk_comb(inst s1 f2, [g, list_mk_comb(f1, [f, var])])) 404 end 405 val goals = map create_goal lower_triangle 406 val fupdcanon_thms = map (C (curry prove) tactic) goals 407 val fupdcanon_thm = 408 if length fupdcanon_thms > 0 then 409 save_thm(typename^"_fupdcanon", 410 LIST_CONJ (map GEN_ALL fupdcanon_thms)) 411 else TRUTH 412 val fupdcanon_comp_thm = 413 if length fupdcanon_thms > 0 then 414 save_thm(typename^"_fupdcanon_comp", 415 LIST_CONJ (map munge_to_composition fupdcanon_thms)) 416 else TRUTH 417 418 val oneone_thm = valOf (TypeBasePure.one_one_of tyinfo) 419 420 (* prove that equality of values is equivalent to equality of fields: 421 i.e. for a record type with two fields: 422 !r1 r2. (r1 = r2) = (r1.fld1 = r2.fld1) /\ (r1.fld2 = r2.fld2) 423 *) 424 local 425 val var1 = mk_var(app_letter typ ^ "1", typ) 426 val var2 = mk_var(app_letter typ ^ "2", typ) 427 val lhs = mk_eq(var1, var2) 428 val rhs_tms = 429 map (fn tm => mk_eq(mk_comb(tm, var1), mk_comb(tm, var2))) 430 accfn_terms 431 val rhs = list_mk_conj rhs_tms 432 val thmname = typename ^ "_component_equality" 433 val goal = mk_eq(lhs, rhs) 434 val tactic = 435 REPEAT GEN_TAC THEN 436 MAP_EVERY (STRUCT_CASES_TAC o C SPEC cases_thm) [var1, var2] THEN 437 REWRITE_TAC [oneone_thm, accessor_thm] 438 val thm0 = prove(goal, tactic) 439 in 440 val component_wise_equality = 441 save_thm(thmname, GENL [var1, var2] thm0) 442 end 443 444 (* prove 445 446 1. that a complete chain of updates over any value is 447 equivalent to a chain of updates over ARB. This particular 448 formulation is chosen to help the pretty-printer, which 449 will print such updates over ARB as record literals. 450 e.g. 451 r1 with <| fld1 := v1 ; fld2 := v2 |> = 452 <| fld1 := v1; fld2 := v2 |> 453 2. prove a version of the nchotomy theorem that uses literal 454 notation rather than the underlying notation involving the 455 constructor 456 e.g., 457 !r. ?v1 v2 v3. r = <| fld1 := v1; fld2 := v2; fld3 := v3 |> 458 459 3. a FORALL_RECD theorem of the form 460 (!r. P r) = 461 (!v1 v2 v3. P <| fld1 := v1; fld2 := v2; fld3 := v3 |>) 462 463 4. likewise, an EXISTS_RECD 464 465 5. one-one ness for literals 466 (<| fld1 := v11; fld2 := v21; fld3 := v31 |> = 467 <| fld1 := v12; fld2 := v22; fld3 := v32 |>) = 468 (v11 = v12) /\ (v21 = v22) /\ (v31 = v32) 469 *) 470 local 471 fun mk_var_avds (nm, ty, avoids) = let 472 val v0 = mk_var(nm, ty) 473 in 474 variant avoids v0 475 end 476 477 fun rng_of_dom ty = ty |> dom_rng |> #1 |> dom_rng |> #2 478 fun dom_of_dom ty = ty |> dom_rng |> #1 |> dom_rng |> #1 479 val value_vars = 480 List.foldr 481 (fn ((_,updt), sofar) => 482 let val ty = rng_of_dom (type_of updt) 483 in 484 mk_var_avds(app_letter ty, ty, var::sofar)::sofar 485 end) 486 [var] fupdfn_terms |> (fn l => List.take(l, length fields)) 487 fun augvar n v = let 488 val (nm, ty) = dest_var v 489 in 490 mk_var(nm ^ Int.toString n, ty) 491 end 492 val vvars1 = map (augvar 1) value_vars 493 val vvars2 = map (augvar 2) value_vars 494 val arb = mk_arb typ 495 fun foldthis ((s,upd),v,(s0,acc)) = let 496 val ty = type_of v 497 val K = Term.inst [alpha |-> ty, beta |-> dom_of_dom (type_of upd)] K_tm 498 in 499 (s @ s0,mk_comb(mk_comb(inst s0 upd, mk_comb(K, v)), acc)) 500 end 501 val (_, lhs) = ListPair.foldr foldthis ([], var) (fupdfn_terms, value_vars) 502 val (_, rhs) = ListPair.foldr foldthis ([], arb) (fupdfn_terms, value_vars) 503 504 val (_, lit1) = ListPair.foldr foldthis ([], arb) (fupdfn_terms, vvars1) 505 val (_, lit2) = ListPair.foldr foldthis ([], arb) (fupdfn_terms, vvars2) 506 507 val literal_equality = 508 GENL (var::value_vars) 509 (prove(mk_eq(lhs, rhs), 510 MAP_EVERY (STRUCT_CASES_TAC o 511 C SPEC cases_thm) [arb, var] THEN 512 REWRITE_TAC [fupdfn_thm, combinTheory.K_THM])) 513 514 val var' = inst tysigma var 515 val typ' = type_of var' 516 val literal_nchotomy = 517 GEN var' 518 (prove(list_mk_exists(value_vars, mk_eq(var', rhs)), 519 MAP_EVERY (STRUCT_CASES_TAC o C ISPEC cases_thm) 520 [arb, var'] THEN 521 REWRITE_TAC [fupdfn_thm, accessor_thm, oneone_thm, 522 combinTheory.K_THM] THEN 523 REPEAT Unwind.UNWIND_EXISTS_TAC)) 524 525 val pred_r = mk_var_avds("P", typ' --> bool, var::value_vars) 526 val P_r = mk_comb(pred_r, var') 527 val P_literal = mk_comb(pred_r, rhs) 528 val forall_goal = mk_eq(mk_forall(var', P_r), 529 list_mk_forall(value_vars, P_literal)) 530 val exists_goal = mk_eq(mk_exists(var', P_r), 531 list_mk_exists(value_vars, P_literal)) 532 val forall_thm = 533 GEN_ALL 534 (prove(forall_goal, 535 EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC [] THEN 536 X_GEN_TAC var' THEN 537 STRUCT_CASES_TAC (ISPEC var' literal_nchotomy) THEN 538 ASM_REWRITE_TAC [])) 539 val exists_thm = 540 GEN_ALL 541 (prove(exists_goal, 542 EQ_TAC THENL [ 543 DISCH_THEN (X_CHOOSE_THEN var' ASSUME_TAC) THEN 544 EVERY_TCL (map X_CHOOSE_THEN value_vars) 545 SUBST_ALL_TAC (ISPEC var' literal_nchotomy) THEN 546 MAP_EVERY EXISTS_TAC value_vars THEN ASM_REWRITE_TAC [], 547 DISCH_THEN (EVERY_TCL (map X_CHOOSE_THEN value_vars) 548 ASSUME_TAC) THEN 549 EXISTS_TAC rhs THEN ASM_REWRITE_TAC [] 550 ])) 551 552 val literal_11 = 553 GENL (vvars1 @ vvars2) 554 (REWRITE_RULE [accfupd_thm, combinTheory.K_THM] 555 (ISPECL [lit1, lit2] component_wise_equality)) 556 557 in 558 val literal_equality = 559 save_thm(typename ^ "_updates_eq_literal", literal_equality) 560 val literal_nchotomy = 561 save_thm(typename ^ "_literal_nchotomy", literal_nchotomy) 562 val forall_thm = save_thm("FORALL_" ^ typename, forall_thm) 563 val exists_thm = save_thm("EXISTS_"^ typename, exists_thm) 564 val literal_11 = save_thm(typename ^ "_literal_11", literal_11) 565 end 566 567 (* add to the TypeBase's simpls entry for the record type *) 568 val new_simpls = let 569 val new_simpls0 = [accessor_thm, accfupd_thm, 570 literal_equality, literal_11, fupdfupd_thm, 571 fupdfupds_comp_thm] 572 in 573 if not (null fupdcanon_thms) then 574 fupdcanon_thm :: fupdcanon_comp_thm :: new_simpls0 575 else new_simpls0 576 end 577 val new_tyinfo = 578 update_tyinfo (SOME (zip fields types,access_defns,fupdfn_thms)) 579 new_simpls tyinfo 580 581 (* set up parsing for the record type *) 582 val brss = GrammarSpecials.bigrec_subdivider_string 583 val _ = 584 if List.exists (is_substring brss) (typename :: fields) then 585 () 586 else let 587 fun do_fupdfn (name0, (_, tm)) = 588 let val name = name0 ^ "_fupd" 589 in 590 Parse.overload_on(name, tm) 591 end 592 in 593 ListPair.app add_record_field (fields, accfn_terms); 594 (* overload strings of the form fld_fupd to refer to the 595 real fupdate functions, which have names of the form 596 type_fld_fupd. Make sure that this overloading is 597 done before the add_record_fupdate function is called 598 because this will also overload this constant to the 599 "artificial" constant for special printing of record 600 syntax, and we want this to be preferred where 601 possible. *) 602 ListPair.app do_fupdfn (fields, fupdfn_terms); 603 ListPair.app (fn (n,(_,t)) => add_record_fupdate(n,t)) 604 (fields, fupdfn_terms); 605 Parse.overload_on(typename, constructor) 606 end 607in 608 new_tyinfo 609end 610 611end (* struct *) 612