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