1(* ========================================================================= *)
2(* ML UTILITY FUNCTIONS                                                      *)
3(* Copyright (c) 2001-2004 Joe Hurd, distributed under the GNU GPL version 2 *)
4(* ========================================================================= *)
5
6structure Useful :> Useful =
7struct
8
9infixr 0 oo ## |->
10
11(* ------------------------------------------------------------------------- *)
12(* Constants                                                                 *)
13(* ------------------------------------------------------------------------- *)
14
15val LINE_LENGTH = ref 75;
16
17(* ------------------------------------------------------------------------- *)
18(* Exceptions                                                                *)
19(* ------------------------------------------------------------------------- *)
20
21exception Error of string;
22
23exception Bug of string;
24
25fun Error_to_string (Error message) = "\nError: " ^ message ^ "\n"
26  | Error_to_string _ = raise Bug "Error_to_string: not an Error exception";
27
28fun Bug_to_string (Bug message) = "\nBug: " ^ message ^ "\n"
29  | Bug_to_string _ = raise Bug "Bug_to_string: not a Bug exception";
30
31fun report (e as Error _) = Error_to_string e
32  | report (e as Bug _) = Bug_to_string e
33  | report _ = raise Bug "report: not an Error or Bug exception";
34
35fun assert b e = if b then () else raise e;
36
37fun try f a = f a
38  handle h as Error _ => (print (Error_to_string h); raise h)
39       | b as Bug _ => (print (Bug_to_string b); raise b)
40       | e => (print "\ntry: strange exception raised\n"; raise e);
41
42fun total f x = SOME (f x) handle Error _ => NONE;
43
44fun can f = Option.isSome o total f;
45
46fun partial (e as Error _) f x = (case f x of SOME y => y | NONE => raise e)
47  | partial _ _ _ = raise Bug "partial: must take an Error exception";
48
49(* ------------------------------------------------------------------------- *)
50(* Profiling                                                                 *)
51(* ------------------------------------------------------------------------- *)
52
53fun timed f a =
54  let
55    val tmr = Timer.startCPUTimer ()
56    val res = f a
57    val {usr,sys,...} = Timer.checkCPUTimer tmr
58  in
59    (Time.toReal usr + Time.toReal sys, res)
60  end;
61
62local
63  val MIN = 1.0;
64
65  fun several n t f a =
66    let
67      val (t',res) = timed f a
68      val t = t + t'
69      val n = n + 1
70    in
71      if t > MIN then (t / Real.fromInt n, res) else several n t f a
72    end;
73in
74  fun timed_many f a = several 0 0.0 f a
75end;
76
77local
78  val max_benchmark_seconds = ref NONE;
79in
80  fun set_benchmark_seconds secs = max_benchmark_seconds := SOME secs;
81
82  val check_benchmark_time =
83      let
84        val start_time = Time.now ()
85
86        fun check () =
87            case !max_benchmark_seconds of
88              NONE => ()
89            | SOME secs =>
90              let
91                val max_benchmark_time = Time.fromReal (Real.fromInt secs)
92                val termination_time = Time.+ (start_time,max_benchmark_time)
93              in
94                if Time.< (Time.now (), termination_time) then ()
95                else OS.Process.exit OS.Process.success
96              end
97      in
98        check
99      end;
100end;
101
102(* ------------------------------------------------------------------------- *)
103(* Tracing                                                                   *)
104(* ------------------------------------------------------------------------- *)
105
106val trace_print = ref print;
107
108val trace_level = ref 1;
109
110val trace_align : {module : string, alignment : int -> int option} list ref
111  = ref [];
112
113local
114  val MAX = 10;
115  fun query m l t =
116      case List.find (fn {module, ...} => module = m) (!trace_align) of
117        NONE => l <= t
118      | SOME {alignment,...} =>
119        case alignment l of NONE => false | SOME l => l <= t;
120in
121  fun tracing {module = m, level = l} =
122    let val t = !trace_level
123    in 0 < t andalso (MAX <= t orelse MAX <= l orelse query m l t)
124    end;
125end;
126
127fun trace message = !trace_print message;
128
129(* ------------------------------------------------------------------------- *)
130(* Combinators                                                               *)
131(* ------------------------------------------------------------------------- *)
132
133fun C f x y = f y x;
134
135fun I x = x;
136
137fun K x y = x;
138
139fun S f g x = f x (g x);
140
141fun W f x = f x x;
142
143fun f oo g = fn x => f o (g x);
144
145fun funpow 0 _ x = x
146  | funpow n f x = funpow (n - 1) f (f x);
147
148(* ------------------------------------------------------------------------- *)
149(* Booleans                                                                  *)
150(* ------------------------------------------------------------------------- *)
151
152fun bool_to_string true = "true"
153  | bool_to_string false = "false";
154
155fun non f = not o f;
156
157fun bool_compare (true,false) = LESS
158  | bool_compare (false,true) = GREATER
159  | bool_compare _ = EQUAL;
160
161(* ------------------------------------------------------------------------- *)
162(* Pairs                                                                     *)
163(* ------------------------------------------------------------------------- *)
164
165fun op## (f,g) (x,y) = (f x, g y);
166
167fun D x = (x,x);
168
169fun Df f = f ## f;
170
171fun fst (x,_) = x;
172
173fun snd (_,y) = y;
174
175fun pair x y = (x,y);
176
177fun swap (x,y) = (y,x);
178
179fun curry f x y = f (x,y);
180
181fun uncurry f (x,y) = f x y;
182
183fun equal x y = (x = y);
184
185(* ------------------------------------------------------------------------- *)
186(* State transformers                                                        *)
187(* ------------------------------------------------------------------------- *)
188
189val unit : 'a -> 's -> 'a * 's = pair;
190
191fun bind f (g : 'a -> 's -> 'b * 's) = uncurry g o f;
192
193fun mmap f (m : 's -> 'a * 's) = bind m (unit o f);
194
195fun mjoin (f : 's -> ('s -> 'a * 's) * 's) = bind f I;
196
197fun mwhile c b = let fun f a = if c a then bind (b a) f else unit a in f end;
198
199(* ------------------------------------------------------------------------- *)
200(* Lists                                                                     *)
201(* ------------------------------------------------------------------------- *)
202
203fun cons x y = x :: y;
204
205fun hd_tl l = (hd l, tl l);
206
207fun append xs ys = xs @ ys;
208
209fun sing a = [a];
210
211fun first f [] = NONE
212  | first f (x :: xs) = (case f x of NONE => first f xs | s => s);
213
214fun index p =
215  let
216    fun idx _ [] = NONE
217      | idx n (x :: xs) = if p x then SOME n else idx (n + 1) xs
218  in
219    idx 0
220  end;
221
222fun maps (_ : 'a -> 's -> 'b * 's) [] = unit []
223  | maps f (x :: xs) =
224    bind (f x) (fn y => bind (maps f xs) (fn ys => unit (y :: ys)));
225
226fun partial_maps (_ : 'a -> 's -> 'b option * 's) [] = unit []
227  | partial_maps f (x :: xs) =
228    bind
229      (f x)
230      (fn yo =>
231          bind
232            (partial_maps f xs)
233            (fn ys => unit (case yo of NONE => ys | SOME y => y :: ys)));
234
235fun enumerate n = fst o C (maps (fn x => fn m => ((m, x), m + 1))) n;
236
237fun zipwith f =
238    let
239      fun z l [] [] = l
240        | z l (x :: xs) (y :: ys) = z (f x y :: l) xs ys
241        | z _ _ _ = raise Error "zipwith: lists different lengths";
242    in
243      fn xs => fn ys => rev (z [] xs ys)
244    end;
245
246fun zip xs ys = zipwith pair xs ys;
247
248fun unzip ab =
249    foldl (fn ((x, y), (xs, ys)) => (x :: xs, y :: ys)) ([], []) (rev ab);
250
251fun cartwith f =
252  let
253    fun aux _ res _ [] = res
254      | aux xs_copy res [] (y :: yt) = aux xs_copy res xs_copy yt
255      | aux xs_copy res (x :: xt) (ys as y :: _) =
256        aux xs_copy (f x y :: res) xt ys
257  in
258    fn xs => fn ys =>
259    let val xs' = rev xs in aux xs' [] xs' (rev ys) end
260  end;
261
262fun cart xs ys = cartwith pair xs ys;
263
264local
265  fun aux res l 0 = (rev res, l)
266    | aux _ [] _ = raise Subscript
267    | aux res (h :: t) n = aux (h :: res) t (n - 1);
268in
269  fun divide l n = aux [] l n;
270end;
271
272fun update_nth f n l =
273    let
274      val (a,b) = divide l n
275    in
276      case b of [] => raise Subscript | h :: t => a @ (f h :: t)
277    end;
278
279fun delete_nth n l =
280    let
281      val (a,b) = divide l n
282    in
283      case b of [] => raise Subscript | _ :: t => a @ t
284    end;
285
286(* ------------------------------------------------------------------------- *)
287(* Lists-as-sets                                                             *)
288(* ------------------------------------------------------------------------- *)
289
290fun mem x = List.exists (equal x);
291
292fun insert x s = if mem x s then s else x :: s;
293fun delete x s = List.filter (not o equal x) s;
294
295(* Removes duplicates *)
296fun setify s = foldl (fn (v,x) => if mem v x then x else v :: x) [] s;
297
298fun union s t = foldl (fn (v,x) => if mem v t then x else v::x) t (rev s);
299fun intersect s t = foldl (fn (v,x) => if mem v t then v::x else x) [] (rev s);
300fun subtract s t = foldl (fn (v,x) => if mem v t then x else v::x) [] (rev s);
301
302fun subset s t = List.all (fn x => mem x t) s;
303
304fun distinct [] = true
305  | distinct (x :: rest) = not (mem x rest) andalso distinct rest;
306
307(* ------------------------------------------------------------------------- *)
308(* Comparisons.                                                              *)
309(* ------------------------------------------------------------------------- *)
310
311type 'a ordering = 'a * 'a -> order;
312
313fun order_to_string LESS = "LESS"
314  | order_to_string EQUAL = "EQUAL"
315  | order_to_string GREATER = "GREATER";
316
317fun map_order mf f (a,b) = f (mf a, mf b);
318
319fun rev_order f xy =
320    case f xy of LESS => GREATER | EQUAL => EQUAL | GREATER => LESS;
321
322fun lex_order f g ((a,c),(b,d)) = case f (a,b) of EQUAL => g (c,d) | x => x;
323
324fun lex_order2 f = lex_order f f;
325
326fun lex_order3 f =
327    map_order (fn (a,b,c) => (a,(b,c))) (lex_order f (lex_order2 f));
328
329fun lex_seq_order f g (a,b) = lex_order f g ((a,a),(b,b));
330
331fun lex_list_order f =
332    let
333      fun lex [] [] = EQUAL
334        | lex [] (_ :: _) = LESS
335        | lex (_ :: _) [] = GREATER
336        | lex (x :: xs) (y :: ys) = case f (x,y) of EQUAL => lex xs ys | r => r
337    in
338      uncurry lex
339    end;
340
341fun lex_option_order _ (NONE,NONE) = EQUAL
342  | lex_option_order _ (SOME _, NONE) = LESS
343  | lex_option_order _ (NONE, SOME _) = GREATER
344  | lex_option_order cmp (SOME x, SOME y) = cmp (x,y);
345
346(* ------------------------------------------------------------------------- *)
347(* Finding the minimum and maximum element of a list, wrt some order.        *)
348(* ------------------------------------------------------------------------- *)
349
350fun minimum cmp =
351    let
352      fun min_acc (l,m,r) _ [] = (m, List.revAppend (l,r))
353        | min_acc (best as (_,m,_)) l (x :: r) =
354          min_acc (case cmp (x,m) of LESS => (l,x,r) | _ => best) (x :: l) r
355    in
356      fn [] => raise Error "minimum: empty list"
357       | h :: t => min_acc ([],h,t) [h] t
358    end;
359
360fun maximum cmp = minimum (rev_order cmp);
361
362(* ------------------------------------------------------------------------- *)
363(* Merge (for the following merge-sort, but generally useful too).           *)
364(* ------------------------------------------------------------------------- *)
365
366fun merge cmp =
367    let
368      fun mrg acc [] ys = List.revAppend (acc,ys)
369        | mrg acc xs [] = List.revAppend (acc,xs)
370        | mrg acc (xs as x :: xt) (ys as y :: yt) =
371          (case cmp (x,y) of
372             GREATER => mrg (y :: acc) xs yt
373           | _ => mrg (x :: acc) xt ys)
374    in
375      mrg []
376    end;
377
378(* ------------------------------------------------------------------------- *)
379(* Merge sort (stable).                                                      *)
380(* ------------------------------------------------------------------------- *)
381
382fun sort cmp =
383    let
384      fun find_runs acc r rs [] = rev (rev (r :: rs) :: acc)
385        | find_runs acc r rs (x :: xs) =
386          case cmp (r,x) of
387            GREATER => find_runs (rev (r :: rs) :: acc) x [] xs
388          | _ => find_runs acc x (r :: rs) xs
389
390      fun merge_adj acc [] = rev acc
391        | merge_adj acc (xs as [_]) = List.revAppend (acc,xs)
392        | merge_adj acc (x :: y :: xs) = merge_adj (merge cmp x y :: acc) xs
393
394      fun merge_pairs [xs] = xs
395        | merge_pairs l = merge_pairs (merge_adj [] l)
396    in
397      fn [] => []
398       | l as [_] => l
399       | h :: t => merge_pairs (find_runs [] h [] t)
400    end;
401
402fun sort_map _ _ [] = []
403  | sort_map _ _ (l as [_]) = l
404  | sort_map f cmp xs =
405    let
406      fun ncmp ((m,_),(n,_)) = cmp (m,n)
407      val nxs = map (fn x => (f x, x)) xs
408      val nys = sort ncmp nxs
409    in
410      map snd nys
411    end;
412
413(* ------------------------------------------------------------------------- *)
414(* Topological sort                                                          *)
415(* ------------------------------------------------------------------------- *)
416
417fun top_sort cmp parents =
418    let
419      fun f stack (x,(acc,seen)) =
420          if Binaryset.member (stack,x) then raise Error "top_sort: cycle"
421          else if Binaryset.member (seen,x) then (acc,seen)
422          else
423            let
424              val stack = Binaryset.add (stack,x)
425              val (acc,seen) = foldl (f stack) (acc,seen) (parents x)
426              val acc = x :: acc
427              val seen = Binaryset.add (seen,x)
428            in
429              (acc,seen)
430            end
431    in
432      rev o fst o foldl (f (Binaryset.empty cmp)) ([], Binaryset.empty cmp)
433    end
434
435(* ------------------------------------------------------------------------- *)
436(* Integers.                                                                 *)
437(* ------------------------------------------------------------------------- *)
438
439val int_to_string = Int.toString;
440
441fun string_to_int s =
442    case Int.fromString s of SOME n => n | NONE => raise Error "string_to_int";
443
444fun int_to_bits 0 = []
445  | int_to_bits n = (n mod 2 <> 0) :: (int_to_bits (n div 2));
446
447fun bits_to_int [] = 0
448  | bits_to_int (h :: t) = (if h then curry op+ 1 else I) (2 * bits_to_int t);
449
450local
451  val enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
452
453  val (max,rev_enc) =
454      foldl
455        (fn (c,(i,m)) => (i + 1, Binarymap.insert (m,c,i)))
456        (0, Binarymap.mkDict Char.compare) (String.explode enc);
457in
458  fun int_to_base64 n =
459      if 0 <= n andalso n < max then String.sub (enc,n)
460      else raise Error "int_to_base64: out of range";
461
462  fun base64_to_int c =
463      case Binarymap.peek (rev_enc, c) of
464        SOME n => n
465      | NONE => raise Error "base64_to_int: out of range";
466end;
467
468fun interval m 0 = []
469  | interval m len = m :: interval (m + 1) (len - 1);
470
471fun divides a b = if a = 0 then b = 0 else b mod (Int.abs a) = 0;
472
473fun even n = divides 2 n;
474
475fun odd n = not (even n);
476
477local
478  fun both f g n = f n andalso g n;
479
480  fun next f = let fun nx x = if f x then x else nx (x + 1) in nx end;
481
482  fun looking res 0 _ _ = rev res
483    | looking res n f x =
484      let
485        val p = next f x
486        val res' = p :: res
487        val f' = both f (not o divides p)
488      in
489        looking res' (n - 1) f' (p + 1)
490      end;
491
492  fun calc_primes n = looking [] n (K true) 2
493
494  val primes_list = ref (calc_primes 10);
495in
496  fun primes n =
497      if length (!primes_list) <= n then List.take (!primes_list,n)
498      else
499        let
500          val l = calc_primes n
501          val () = primes_list := l
502        in
503          l
504        end;
505
506  fun primes_up_to n =
507      let
508        fun f k [] =
509            let
510              val l = calc_primes (2 * k)
511              val () = primes_list := l
512            in
513              f k (List.drop (l,k))
514            end
515          | f k (p :: ps) =
516            if p <= n then f (k + 1) ps else List.take (!primes_list, k)
517      in
518        f 0 (!primes_list)
519      end;
520end;
521
522local
523  fun hcf 0 n = n | hcf 1 _ = 1 | hcf m n = hcf (n mod m) m;
524in
525  fun gcd m n =
526      let
527        val m = Int.abs m
528        val n = Int.abs n
529      in
530        if m < n then hcf m n else hcf n m
531      end;
532end;
533
534(* ------------------------------------------------------------------------- *)
535(* Strings                                                                   *)
536(* ------------------------------------------------------------------------- *)
537
538local
539  fun len l = (length l, l)
540  val upper = len (explode "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
541  val lower = len (explode "abcdefghijklmnopqrstuvwxyz");
542  fun rotate (n,l) c k = List.nth (l, (k+Option.valOf(index(equal c)l)) mod n);
543in
544  fun rot k c =
545    if Char.isLower c then rotate lower c k
546    else if Char.isUpper c then rotate upper c k
547    else c;
548end;
549
550fun nchars x =
551    let
552      fun dup _ 0 l = l | dup x n l = dup x (n - 1) (x :: l)
553    in
554      fn n => implode (dup x n [])
555    end;
556
557fun chomp s =
558    let
559      val n = size s
560    in
561      if n = 0 orelse String.sub (s, n - 1) <> #"\n" then s
562      else String.substring (s, 0, n - 1)
563    end;
564
565local
566  fun chop [] = []
567    | chop (l as (h :: t)) = if Char.isSpace h then chop t else l;
568in
569  val trim = implode o chop o rev o chop o rev o explode;
570end;
571
572fun join _ [] = "" | join s (h :: t) = foldl (fn (x,y) => y ^ s ^ x) h t;
573
574local
575  fun match [] l = SOME l
576    | match _ [] = NONE
577    | match (x :: xs) (y :: ys) = if x = y then match xs ys else NONE;
578
579  fun stringify acc [] = acc
580    | stringify acc (h :: t) = stringify (implode h :: acc) t;
581in
582  fun split sep =
583      let
584        val pat = String.explode sep
585        fun div1 prev recent [] = stringify [] (rev recent :: prev)
586          | div1 prev recent (l as h :: t) =
587            case match pat l of
588              NONE => div1 prev (h :: recent) t
589            | SOME rest => div1 (rev recent :: prev) [] rest
590      in
591        fn s => div1 [] [] (explode s)
592      end;
593end;
594
595fun pluralize {singular,plural} = fn 1 => singular | _ => plural;
596
597fun variant x vars = if mem x vars then variant (x ^ "'") vars else x;
598
599fun variant_num x vars =
600    let
601      fun xn n = x ^ int_to_string n
602      fun v n = let val x' = xn n in if mem x' vars then v (n + 1) else x' end
603    in
604      if mem x vars then v 1 else x
605    end;
606
607fun dest_prefix p =
608    let
609      fun check s = assert (String.isPrefix p s) (Error "dest_prefix")
610      val size_p = size p
611    in
612      fn s => (check s; String.extract (s, size_p, NONE))
613    end;
614
615fun is_prefix p = can (dest_prefix p);
616
617fun mk_prefix p s = p ^ s;
618
619fun align_table {left,pad} =
620    let
621      fun pad_col n s =
622          let
623            val p = nchars pad (n - size s)
624          in
625            if left then s ^ p else p ^ s
626          end
627
628      fun pad_cols (l as [] :: _) = map (K "") l
629        | pad_cols l =
630          let
631            val hs = map hd l
632            val (n,_) = minimum (Int.compare o swap) (map size hs)
633            val last_left = left andalso length (hd l) = 1
634            val hs = if last_left then hs else map (pad_col n) hs
635          in
636            zipwith (fn x => fn y => x ^ y) hs (pad_cols (map tl l))
637          end
638    in
639      pad_cols
640    end;
641
642(* ------------------------------------------------------------------------- *)
643(* Reals.                                                                    *)
644(* ------------------------------------------------------------------------- *)
645
646val real_to_string = Real.toString;
647
648fun percent_to_string x = int_to_string (Real.round (100.0 * x)) ^ "%";
649
650fun pos r = Real.max (r,0.0);
651
652local val ln2 = Math.ln 2.0 in fun log2 x = Math.ln x / ln2 end;
653
654(* ------------------------------------------------------------------------- *)
655(* Pretty-printing.                                                          *)
656(* ------------------------------------------------------------------------- *)
657
658(* Generic pretty-printers *)
659
660type 'a pp = ppstream -> 'a -> unit;
661
662fun pp_map f pp_a (ppstrm : ppstream) x : unit = pp_a ppstrm (f x);
663
664fun pp_bracket l r pp_a pp a =
665    (PP.begin_block pp PP.INCONSISTENT (size l); PP.add_string pp l; pp_a pp a;
666     PP.add_string pp r; PP.end_block pp);
667
668fun pp_sequence sep pp_a pp =
669    let
670      fun pp_x x = (PP.add_string pp sep; PP.add_break pp (1,0); pp_a pp x)
671    in
672      fn [] => () | h :: t => (pp_a pp h; app pp_x t)
673    end;
674
675fun pp_binop s pp_a pp_b pp (a,b) =
676    (PP.begin_block pp PP.INCONSISTENT 0;
677     pp_a pp a;
678     PP.add_string pp s;
679     PP.add_break pp (1,0);
680     pp_b pp b;
681     PP.end_block pp);
682
683(* Pretty-printers for common types *)
684
685fun pp_string pp s =
686    (PP.begin_block pp PP.INCONSISTENT 0;
687     PP.add_string pp s;
688     PP.end_block pp);
689
690val pp_unit = pp_map (fn () => "()") pp_string;
691
692val pp_char = pp_map str pp_string;
693
694val pp_bool = pp_map bool_to_string pp_string;
695
696val pp_int = pp_map int_to_string pp_string;
697
698val pp_real = pp_map real_to_string pp_string;
699
700val pp_order = pp_map order_to_string pp_string;
701
702val pp_porder =
703    pp_map (fn NONE => "INCOMPARABLE" | SOME x => order_to_string x) pp_string;
704
705fun pp_list pp_a = pp_bracket "[" "]" (pp_sequence "," pp_a);
706
707fun pp_pair pp_a pp_b = pp_bracket "(" ")" (pp_binop "," pp_a pp_b);
708
709fun pp_triple pp_a pp_b pp_c =
710    pp_bracket
711      "(" ")"
712      (pp_map
713         (fn (a,b,c) => (a,(b,c)))
714         (pp_binop "," pp_a (pp_binop "," pp_b pp_c)));
715
716fun toString pp_a a = PP.pp_to_string (!LINE_LENGTH) pp_a a;
717
718fun varToString pp_x name_x x =
719    toString (pp_binop " =" pp_string pp_x) (name_x,x);
720
721(* ------------------------------------------------------------------------- *)
722(* Sums                                                                      *)
723(* ------------------------------------------------------------------------- *)
724
725datatype ('a,'b) sum = INL of 'a | INR of 'b
726
727fun is_inl (INL _) = true | is_inl (INR _) = false;
728
729fun is_inr (INR _) = true | is_inr (INL _) = false;
730
731fun pp_sum pp_a _ pp (INL a) = pp_a pp a
732  | pp_sum _ pp_b pp (INR b) = pp_b pp b;
733
734(* ------------------------------------------------------------------------- *)
735(* Maplets.                                                                  *)
736(* ------------------------------------------------------------------------- *)
737
738datatype ('a,'b) maplet = op|-> of 'a * 'b;
739
740fun pp_maplet pp_a pp_b =
741    pp_map (fn a |-> b => (a, b)) (pp_binop " |->" pp_a pp_b);
742
743(* ------------------------------------------------------------------------- *)
744(* Useful impure features                                                    *)
745(* ------------------------------------------------------------------------- *)
746
747fun memoize f = let val s = Susp.delay f in fn () => Susp.force s end;
748
749local
750  val generator = ref 0
751in
752  fun new_int () =
753      let
754        val n = !generator
755        val () = generator := n + 1
756      in
757        n
758      end;
759
760  fun new_ints 0 = []
761    | new_ints k =
762      let
763        val n = !generator
764        val () = generator := n + k
765      in
766        interval n k
767      end;
768end;
769
770local
771  val gen = Random.newgenseed 1.0;
772in
773  fun random max = Random.range (0,max) gen;
774
775  fun uniform () = Random.random gen;
776
777  fun coin_flip () = Random.range (0,2) gen = 0;
778end;
779
780fun with_flag (r,update) f x =
781  let
782    val old = !r
783    val () = r := update old
784    val y = f x handle e => (r := old; raise e)
785    val () = r := old
786  in
787    y
788  end;
789
790fun cached cmp f =
791    let
792      val cache = ref (Binarymap.mkDict cmp)
793    in
794      fn x =>
795      case Binarymap.peek (!cache,x) of
796        SOME y => y
797      | NONE =>
798        let
799          val y = f x
800          val () = cache := Binarymap.insert (!cache,x,y)
801        in
802          y
803        end
804    end;
805
806(* ------------------------------------------------------------------------- *)
807(* Environment.                                                              *)
808(* ------------------------------------------------------------------------- *)
809
810val host = Option.getOpt (OS.Process.getEnv "HOSTNAME", "unknown");
811
812val date = Date.fmt "%H:%M:%S %d/%m/%Y" o Date.fromTimeLocal o Time.now;
813
814val today = Date.fmt "%d/%m/%Y" o Date.fromTimeLocal o Time.now;
815
816local
817  fun err x s = TextIO.output (TextIO.stdErr, x ^ ": " ^ s ^ "\n");
818in
819  val warn = err "WARNING";
820  fun die s = (err "\nFATAL ERROR" s; OS.Process.exit OS.Process.failure);
821end
822
823fun read_textfile {filename} =
824  let
825    open TextIO
826    val h = openIn filename
827    val contents = inputAll h
828    val () = closeIn h
829  in
830    contents
831  end;
832
833fun write_textfile {filename,contents} =
834  let
835    open TextIO
836    val h = openOut filename
837    val () = output (h,contents)
838    val () = closeOut h
839  in
840    ()
841  end;
842
843end
844