1(* ========================================================================= *) 2(* THE MESON PROOF PROCEDURE *) 3(* Copyright (c) 2001-2004 Joe Hurd. *) 4(* ========================================================================= *) 5 6(* 7app load 8 ["mlibUseful", "mlibStream", "Mosml", "mlibTerm", "mlibThm", "mlibCanon", "mlibMatch", 9 "mlibSolver", "mlibMeter", "mlibUnits"]; 10*) 11 12(* 13*) 14structure mlibMeson :> mlibMeson = 15struct 16 17open mlibUseful mlibTerm mlibMatch mlibThm mlibCanon mlibMeter mlibSolver; 18 19structure S = mlibStream; local open mlibStream in end; 20structure N = mlibLiteralnet; local open mlibLiteralnet in end; 21structure U = mlibUnits; local open mlibUnits in end; 22 23val |<>| = mlibSubst.|<>|; 24val formula_subst = mlibSubst.formula_subst; 25 26(* ------------------------------------------------------------------------- *) 27(* Chatting. *) 28(* ------------------------------------------------------------------------- *) 29 30val module = "mlibMeson"; 31val () = add_trace {module = module, alignment = I} 32fun chatting l = tracing {module = module, level = l}; 33fun chat s = (trace s; true) 34 35(* ------------------------------------------------------------------------- *) 36(* Tuning parameters. *) 37(* ------------------------------------------------------------------------- *) 38 39type parameters = 40 {ancestor_pruning : bool, 41 ancestor_cutting : bool, 42 state_simplify : bool, 43 cache_cutting : bool, 44 divide_conquer : bool, 45 unit_lemmaizing : bool, 46 sort_literals : int, 47 sort_rules : bool}; 48 49val defaults = 50 {ancestor_pruning = true, 51 ancestor_cutting = true, 52 state_simplify = true, 53 cache_cutting = false, 54 divide_conquer = false, 55 unit_lemmaizing = true, 56 sort_literals = 1, 57 sort_rules = true}; 58 59type 'a Parmupdate = ('a -> 'a) -> parameters -> parameters 60 61fun update_ancestor_pruning f (parm : parameters) : parameters = 62 let 63 val {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 64 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 65 sort_literals = l, sort_rules = r} = parm 66 in 67 {ancestor_pruning = f a, ancestor_cutting = b, state_simplify = s, 68 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 69 sort_literals = l, sort_rules = r} 70 end; 71 72fun update_ancestor_cutting f (parm : parameters) : parameters = 73 let 74 val {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 75 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 76 sort_literals = l, sort_rules = r} = parm 77 in 78 {ancestor_pruning = a, ancestor_cutting = f b, state_simplify = s, 79 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 80 sort_literals = l, sort_rules = r} 81 end; 82 83fun update_state_simplify f (parm : parameters) : parameters = 84 let 85 val {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 86 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 87 sort_literals = l, sort_rules = r} = parm 88 in 89 {ancestor_pruning = a, ancestor_cutting = b, state_simplify = f s, 90 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 91 sort_literals = l, sort_rules = r} 92 end; 93 94fun update_cache_cutting f (parm : parameters) : parameters = 95 let 96 val {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 97 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 98 sort_literals = l, sort_rules = r} = parm 99 in 100 {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 101 cache_cutting = f c, divide_conquer = d, unit_lemmaizing = u, 102 sort_literals = l, sort_rules = r} 103 end; 104 105fun update_divide_conquer f (parm : parameters) : parameters = 106 let 107 val {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 108 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 109 sort_literals = l, sort_rules = r} = parm 110 in 111 {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 112 cache_cutting = c, divide_conquer = f d, unit_lemmaizing = u, 113 sort_literals = l, sort_rules = r} 114 end; 115 116fun update_unit_lemmaizing f (parm : parameters) : parameters = 117 let 118 val {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 119 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 120 sort_literals = l, sort_rules = r} = parm 121 in 122 {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 123 cache_cutting = c, divide_conquer = d, unit_lemmaizing = f u, 124 sort_literals = l, sort_rules = r} 125 end; 126 127fun update_sort_literals f (parm : parameters) : parameters = 128 let 129 val {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 130 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 131 sort_literals = l, sort_rules = r} = parm 132 in 133 {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 134 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 135 sort_literals = f l, sort_rules = r} 136 end; 137 138fun update_sort_rules f (parm : parameters) : parameters = 139 let 140 val {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 141 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 142 sort_literals = l, sort_rules = r} = parm 143 in 144 {ancestor_pruning = a, ancestor_cutting = b, state_simplify = s, 145 cache_cutting = c, divide_conquer = d, unit_lemmaizing = u, 146 sort_literals = l, sort_rules = f r} 147 end; 148 149(* ------------------------------------------------------------------------- *) 150(* Helper functions. *) 151(* ------------------------------------------------------------------------- *) 152 153fun halves n = let val n1 = n div 2 in (n1, n - n1) end; 154 155fun divisible [] = false 156 | divisible [_] = false 157 | divisible _ = true; 158 159local 160 val prefix = "_m"; 161in 162 val mk_mvar = mk_prefix prefix o int_to_string; 163 fun mk_mvars n i = map (Var o mk_mvar) (interval n i); 164 val dest_mvar = string_to_int o dest_prefix prefix; 165end; 166 167local 168 fun sz n [] = n 169 | sz n (Fn (":", [tm, _]) :: tms) = sz n (tm :: tms) 170 | sz n (Var _ :: tms) = sz (n + 1) tms 171 | sz n (Fn (_,l) :: tms) = sz (n + 1) (l @ tms); 172in 173 fun literal_size False = 0 174 | literal_size lit = sz 0 [dest_atom (literal_atom lit)]; 175end; 176 177datatype 'a choice = CHOICE of unit -> 'a * 'a choice; 178 179fun dest_choice (CHOICE c) = c; 180 181val no_choice = (fn () => raise Error "no_choice: always fails"); 182 183fun binary_choice f g = 184 (fn () => 185 let val (a, c) = f () in (a, CHOICE (binary_choice (dest_choice c) g)) end 186 handle Error _ => g ()); 187 188fun first_choice [] = no_choice 189 | first_choice [f] = f 190 | first_choice (f :: fs) = binary_choice f (first_choice fs); 191 192fun choice_stream f = 193 let val (a, CHOICE c) = f () in S.CONS (a, fn () => choice_stream c) end 194 handle Error _ => S.NIL; 195 196fun swivel m n l = 197 let 198 val (l1, l') = divide l m 199 val (l2, l3) = divide l' n 200 in 201 l2 @ l1 @ l3 202 end; 203 204fun thm_proves th False = is_contradiction th 205 | thm_proves th goal = 206 case clause th of [lit] => lit = goal | [] => true | _ => false; 207 208fun filter_meter meter = 209 S.filter (fn a => Option.isSome a orelse not (check_meter (Uref.!meter))); 210 211(* ------------------------------------------------------------------------- *) 212(* mlibMeson rules. *) 213(* ------------------------------------------------------------------------- *) 214 215type rule = {asms : formula list, c : formula, thm : thm, asmn : int}; 216 217datatype rules = Rules of rule N.literalnet; 218 219fun dest_rules (Rules r) = r; 220val empty_rules = Rules (N.empty {fifo = true}); 221fun add_rule r (Rules n) = Rules (N.insert r n); 222val num_all_rules = N.size o dest_rules; 223val num_initial_rules = #f o N.size_profile o dest_rules; 224fun num_rules r = num_all_rules r - num_initial_rules r; 225fun rules_unify r = N.unify (dest_rules r); 226 227local fun dest ({asms, c, ...} : rule) = (asms,c); 228in val pp_rule = pp_map dest (pp_binop " ==>" (pp_list pp_formula) pp_formula); 229end; 230 231fun rule_to_string r = PP.pp_to_string (!LINE_LENGTH) pp_rule r; 232 233val pp_rules = 234 pp_map (map (fn _ |-> x => x) o N.to_maplets o dest_rules) 235 (pp_list pp_rule); 236 237(* ------------------------------------------------------------------------- *) 238(* Sorting literals within rules. *) 239(* ------------------------------------------------------------------------- *) 240 241val sort_lits = sort_map literal_size (rev_order Int.compare); 242 243(* ------------------------------------------------------------------------- *) 244(* Sorting rules. *) 245(* ------------------------------------------------------------------------- *) 246 247local 248 fun quality (_ |-> ({asmn, c, ...} : rule)) = (asmn, literal_size c); 249 val qualitywise = lex_order Int.compare (rev_order Int.compare); 250in 251 val sort_ruls = sort_map quality qualitywise; 252end; 253 254(* ------------------------------------------------------------------------- *) 255(* Compiling the rule set used by meson. *) 256(* ------------------------------------------------------------------------- *) 257 258fun mk_contrapositives chosen opt sos th = 259 let 260 val th = FRESH_VARS th 261 val lits = clause th 262 val lits' = map negate lits 263 fun g l = (List.filter (not o equal (negate l)) lits', l) 264 val base = map g (chosen lits) 265 val contrs = if sos then (lits', False) :: base else base 266 fun f (a,c) = c |-> {asms = opt a, c = c, thm = th, asmn = length a} 267 in 268 map f contrs 269 end; 270 271fun thms_to_rules parm chosen thms hyps = 272 let 273 val {sort_literals, sort_rules, ...} : parameters = parm 274 val opt = if 1 <= sort_literals then sort_lits else I 275 fun f sos (th,l) = mk_contrapositives chosen opt sos th @ l 276 val contrs = rev (foldl (f true) (foldl (f false) [] thms) hyps) 277 val contrs = if sort_rules then sort_ruls contrs else contrs 278 in 279 foldl (fn (h,t) => add_rule h t) empty_rules contrs 280 end; 281 282fun meson_rules parm = thms_to_rules parm I; 283 284local 285 fun only_one (l as [_]) = l | only_one _ = []; 286 val chosen = only_one o List.filter positive; 287in 288 fun prolog_rules parm = thms_to_rules parm chosen; 289end; 290 291(* ------------------------------------------------------------------------- *) 292(* Creating the delta goals. *) 293(* ------------------------------------------------------------------------- *) 294 295val thms_to_delta_goals = 296 List.concat o 297 map (fn (f,n) => [Atom (Fn (f,new_vars n)), Not (Atom (Fn (f,new_vars n)))]) o 298 foldl (uncurry union) [] o 299 map relations o 300 List.concat o 301 map clause; 302 303(* ------------------------------------------------------------------------- *) 304(* The state passed around by meson. *) 305(* ------------------------------------------------------------------------- *) 306 307type state = {env : subst, depth : int, proof : thm list, offset : int}; 308 309fun update_env f ({env, depth, proof, offset} : state) = 310 {env = f env, depth = depth, proof = proof, offset = offset}; 311 312fun update_depth f ({env, depth, proof, offset} : state) = 313 {env = env, depth = f depth, proof = proof, offset = offset}; 314 315fun update_proof f ({env, depth, proof, offset} : state) = 316 {env = env, depth = depth, proof = f proof, offset = offset}; 317 318fun update_offset f ({env, depth, proof, offset} : state) = 319 {env = env, depth = depth, proof = proof, offset = f offset}; 320 321(* ------------------------------------------------------------------------- *) 322(* Ancestor pruning. *) 323(* ------------------------------------------------------------------------- *) 324 325fun ancestor_prune false _ _ = K false 326 | ancestor_prune true env g = 327 let 328 val g' = formula_subst env g 329 fun check a' = a' = g' 330 in 331 List.exists (check o formula_subst env) 332 end; 333 334(* ------------------------------------------------------------------------- *) 335(* Ancestor cutting. *) 336(* ------------------------------------------------------------------------- *) 337 338fun ancestor_cut false _ _ = K false 339 | ancestor_cut true env g = 340 let 341 val g' = negate (formula_subst env g) 342 fun check a' = a' = g' 343 in 344 List.exists (check o formula_subst env) 345 end; 346 347(* ------------------------------------------------------------------------- *) 348(* Cache cutting. *) 349(* ------------------------------------------------------------------------- *) 350 351fun cache_cont c ({offset, ...} : state) = 352 let 353 fun f v = case total dest_mvar v of NONE => true | SOME n => n < offset 354 val listify = mlibSubst.foldr (fn m as v |-> _ => if f v then cons m else I) [] 355 val mem = ref [] 356 fun purify (s as {env, depth = n, ...} : state) = 357 let 358 val l = listify env 359 fun p (n', l') = n <= n' andalso l = l' 360 in 361 if List.exists p (!mem) then raise Error "cache_cut: repetition" 362 else ( 363 mem := (n, l) :: (!mem); (* OK *) 364 update_env (K (mlibSubst.from_maplets l)) s 365 ) 366 end 367 in 368 c o purify 369 end; 370 371fun cache_cut false = I 372 | cache_cut true = 373 fn f => fn a => fn g => fn c => fn s => f a g (cache_cont c s) s; 374 375(* ------------------------------------------------------------------------- *) 376(* Unit clause shortcut. *) 377(* ------------------------------------------------------------------------- *) 378 379fun grab_unit units (s as {proof = th :: _, ...} : state) = 380 let 381 open Uref 382 val u = !units 383 val th = U.demod u th 384 val () = units := U.add th u (* OK *) 385 in 386 update_proof (cons th o tl) s 387 end 388 | grab_unit _ {proof = [], ...} = raise Bug "grab_unit: no thms"; 389 390fun use_unit units g c (s as {env, ...}) = 391 let 392 val prove = partial (Error "use_unit: NONE") (U.prove (Uref.!units)) 393 in 394 c (update_proof (cons (hd (prove [formula_subst env g]))) s) 395 end; 396 397fun unit_cut false _ = I 398 | unit_cut true units = 399 fn f => fn a => fn g => fn c => fn s => 400 use_unit units g c s handle Error _ => f a g (c o grab_unit units) s; 401 402(* ------------------------------------------------------------------------- *) 403(* The core of meson: ancestor unification or Prolog-style extension. *) 404(* ------------------------------------------------------------------------- *) 405 406local 407 (* Only check the meter every CHECK_PERIOD inferences to save time *) 408 val CHECK_PERIOD = 100; 409in 410 fun meter_expired m = 411 read_infs m mod CHECK_PERIOD = 0 andalso not (check_meter m); 412end; 413 414fun freshen_rule ({thm, asms, c, asmn} : rule) i = 415 let 416 val fvs = FVL [] (c :: asms) 417 val fvn = length fvs 418 val mvs = mk_mvars i fvn 419 val sub = mlibSubst.from_maplets (zipwith (curry op|->) fvs mvs) 420 in 421 ({thm = INST sub thm, asms = map (formula_subst sub) asms, 422 c = formula_subst sub c, asmn = asmn}, i + fvn) 423 end; 424 425fun reward r = update_depth (fn n => n + r); 426 427fun spend m f c (s as {depth = n, ...} : state) = 428 let 429 val low = n - m 430 val () = assert (0 <= low) (Error "meson: impossible divide and conquer") 431 fun check (s' as {depth = n', ...} : state) = 432 if n' <= low then s' else raise Error "meson: divide and conquer" 433 in 434 f (c o check) s 435 end; 436 437local 438 fun unify env ({thm,asms,c,...} : rule) g = 439 (thm, asms, unify_literals env c g); 440 441 fun match env ({thm,asms,c,...} : rule) g = 442 let val sub = match_literals c g 443 in (INST sub thm, map (formula_subst sub) asms, env) 444 end; 445in 446 fun next_state false env r g = unify env r g 447 | next_state true env r g = 448 match env r g handle Error _ => unify env r g; 449end; 450 451local 452 fun mp _ th [] p = FACTOR th :: p 453 | mp env th (g :: gs) (th1 :: p) = 454 mp env (RESOLVE (formula_subst env g) (INST env th1) th) gs p 455 | mp _ _ (_ :: _) [] = raise Bug "modus_ponens: fresh out of thms" 456in 457 fun modus_ponens th gs (state as {env, ...}) = 458 update_proof (mp env (INST env th) (rev gs)) state; 459end; 460 461fun swivelp m n = update_proof (swivel m n); 462 463fun meson_expand {parm : parameters, rules, cut, meter, saturated} = 464 let 465 val {ancestor_pruning, ancestor_cutting, state_simplify, 466 divide_conquer, sort_literals, ...} = parm 467 fun expand ancestors g cont (state as {env, ...}) = 468 (chatting 5 andalso 469 chat ("meson: "^formula_to_string (formula_subst env g)^".\n"); 470 if meter_expired (Uref.!meter) then 471 (NONE, CHOICE (fn () => expand ancestors g cont state)) 472 else if ancestor_prune ancestor_pruning env g ancestors then 473 raise Error "meson: ancestor pruning" 474 else if ancestor_cut ancestor_cutting env g ancestors then 475 cont (update_proof (cons (ASSUME g)) state) 476 else 477 let 478 fun reduction a () = 479 let 480 val state = update_env (K(unify_literals env g (negate a)))state 481 val state = update_proof (cons (ASSUME g)) state 482 in 483 cont state 484 end 485 val expansion = expand_rule ancestors g cont state 486 in 487 first_choice 488 (map reduction ancestors @ 489 map expansion (rules_unify rules (formula_subst env g))) () 490 end) 491 and expand_rule ancestors g cont {env, depth, proof, offset} r () = 492 let 493 open Uref 494 val depth = depth - #asmn r 495 val () = 496 if 0 <= depth then () 497 else (saturated := false; raise Error "meson: too deep") (* OK *) 498 val (r',offset) = freshen_rule r offset 499 val (th,asms,env) = next_state state_simplify env r' g 500 val asms = if 2 <= sort_literals then sort_lits asms else asms 501 val () = record_infs (!meter) 1 502 val _ = chatting 6 andalso chat ("meson rule: "^rule_to_string r^"\n") 503 in 504 expands (g :: ancestors) asms (cont o modus_ponens th asms) 505 {env = env, depth = depth, proof = proof, offset = offset} 506 end 507 and expands ancestors g c (s as {depth = n, ...}) = 508 if divide_conquer andalso divisible g then 509 let 510 val (l1, l2) = halves (length g) 511 val (g1, g2) = divide g l1 512 val (f1, f2) = Df (expands ancestors) (g1, g2) 513 val (n1, n2) = halves n 514 val s = update_depth (K n1) s 515 in 516 binary_choice 517 (fn () => f1 (f2 c o reward n2) s) 518 (fn () => f2 (spend (n1 + 1) f1 (c o swivelp l1 l2) o reward n2) s) () 519 end 520 else foldl (uncurry (cut expand ancestors)) c (rev g) s 521 in 522 cut expand [] 523 end; 524 525(* ------------------------------------------------------------------------- *) 526(* Full meson procedure. *) 527(* ------------------------------------------------------------------------- *) 528 529fun meson_finally g ({env, proof, ...} : state) = 530 let 531 val () = assert (length proof = length g) (Bug "meson: bad final state") 532 val g' = map (formula_subst env) g 533 val proof' = map (INST env) (rev proof) 534 val _ = chatting 4 andalso chat 535 (foldl (fn (h,t)=>t^" "^thm_to_string h^"\n") "meson_finally:\n" proof') 536 val () = 537 assert (List.all (uncurry thm_proves) (zip proof' g')) 538 (Bug "meson: did not prove goal list") 539 in 540 (SOME (FRESH_VARSL proof'), CHOICE no_choice) 541 end; 542 543fun raw_meson system goals depth = 544 choice_stream 545 (fn () => 546 foldl (uncurry (meson_expand system)) (meson_finally goals) (rev goals) 547 {env = |<>|, depth = depth, proof = [], offset = 0}); 548 549(* ------------------------------------------------------------------------- *) 550(* Raw solvers. *) 551(* ------------------------------------------------------------------------- *) 552 553type 'a system = 554 {parm : parameters, rules : rules, meter : meter Uref.t, saturated : bool Uref.t, 555 cut : 556 (formula list -> formula -> (state -> 'a) -> state -> 'a) -> 557 formula list -> formula -> (state -> 'a) -> state -> 'a}; 558 559fun mk_system parm units meter rules : 'a system = 560 let 561 val {cache_cutting = caching, unit_lemmaizing = lemmaizing, ...} = parm 562 in 563 {parm = parm, 564 rules = rules, 565 meter = meter, 566 saturated = Uref.new false, 567 cut = unit_cut lemmaizing units o cache_cut caching} 568 end; 569 570fun meson' (name,parm) = 571 mk_solver_node 572 {name = name, 573 solver_con = 574 fn {slice, units, thms, hyps} => 575 let 576 val ruls = meson_rules parm thms hyps 577 val _ = chatting 3 andalso chat 578 (name ^ "--initializing--#thms=" ^ int_to_string (length thms) ^ 579 "--#hyps=" ^ int_to_string (length hyps) ^ 580 "--#rules=" ^ int_to_string (num_rules ruls) ^ 581 "--#initial_rules=" ^ int_to_string (num_initial_rules ruls) ^ ".\n") 582 val system as {saturated = b, ...} = mk_system parm units slice ruls 583 fun d n = if Uref.!b then S.NIL 584 else (Uref.:=(b, true); S.CONS (n, fn () => d (n + 1))) (* OK *) 585 fun f q d = 586 (chatting 1 andalso chat ("-" ^ int_to_string d); 587 raw_meson system q d) 588 fun unit_check goals NONE = U.prove (Uref.!units) goals | unit_check _ s = s 589 in 590 fn goals => 591 filter_meter slice 592 (S.map (unit_check goals) (S.flatten (S.map (f goals) (d 0)))) 593 end}; 594 595val meson = meson' ("meson",defaults); 596 597fun delta' (name,parm) = 598 mk_solver_node 599 {name = name, 600 solver_con = 601 fn {slice, units, thms, hyps} => 602 let 603 open Uref 604 val ruls = meson_rules parm thms hyps 605 val dgoals = thms_to_delta_goals hyps 606 val _ = chatting 3 andalso chat 607 (name ^ "--initializing--#thms=" ^ int_to_string (length thms) ^ 608 "--#hyps=" ^ int_to_string (length hyps) ^ 609 "--#rules=" ^ int_to_string (num_rules ruls) ^ 610 "--#delta_goals=" ^ int_to_string (length dgoals) ^ ".\n") 611 val system as {saturated = b, ...} = mk_system parm units slice ruls 612 val delta_goals = S.from_list dgoals 613 fun d n = if !b then S.NIL 614 else (b := true; S.CONS (n, fn () => d (n + 1))) (* OK *) 615 fun f d g = 616 (chatting 1 andalso chat "+"; 617 S.map (K NONE) (raw_meson system [g] d)) 618 fun g d = 619 (chatting 1 andalso chat (int_to_string d); 620 S.flatten (S.map (f d) delta_goals)) 621 fun h () = S.flatten (S.map g (d 0)) 622 fun unit_check goals NONE = U.prove (!units) goals | unit_check _ s = s 623 in 624 case delta_goals of S.NIL => K S.NIL 625 | _ => fn goals => filter_meter slice (S.map (unit_check goals) (h ())) 626 end}; 627 628val delta = delta' ("delta",defaults); 629 630val prolog_depth = case Int.maxInt of NONE => 1000000 | SOME i => i; 631 632fun prolog' (name,parm) = 633 mk_solver_node 634 {name = name, 635 solver_con = 636 fn {slice, units, thms, hyps} => 637 let 638 val system = mk_system parm units slice (prolog_rules parm thms hyps) 639 fun comment S.NIL = "!\n" 640 | comment (S.CONS (NONE, _)) = "-" 641 | comment (S.CONS (SOME _, _)) = "$\n" 642 fun f S.NIL = S.NIL | f (S.CONS (x,xs)) = S.CONS (x, fn () => g (xs ())) 643 and g x = (chatting 1 andalso chat (comment x); f x) 644 in 645 fn goals => g (raw_meson system goals prolog_depth) 646 end}; 647 648local val p = update_sort_literals (K 0) (update_sort_rules (K false) defaults); 649in val prolog = prolog' ("prolog",p); 650end; 651 652end 653