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