1(* ===================================================================== *) 2(* FILE : Lib.sml *) 3(* DESCRIPTION : library of useful SML functions. *) 4(* *) 5(* AUTHOR : (c) Konrad Slind, University of Calgary *) 6(* DATE : August 26, 1991 *) 7(* Modified : September 22, 1997, Ken Larsen *) 8(* ===================================================================== *) 9 10structure Lib :> Lib = 11struct 12 13open Feedback; 14 15val ERR = mk_HOL_ERR "Lib" 16 17open Portable; 18datatype frag = datatype HOLPP.frag 19 20(*---------------------------------------------------------------------------* 21 * A version of try that coerces non-HOL_ERR exceptions to be HOL_ERRs. * 22 * To be used with tacticals and the like that get driven by HOL_ERR * 23 * exceptions. * 24 *---------------------------------------------------------------------------*) 25 26local 27 val default_exn = ERR "trye" "original exn. not a HOL_ERR" 28in 29 fun trye f x = 30 f x handle e as HOL_ERR _ => raise e 31 | Interrupt => raise Interrupt 32 | _ => raise default_exn 33end 34 35(*---------------------------------------------------------------------------* 36 * For interactive use: "Raise" prints out the exception. * 37 *---------------------------------------------------------------------------*) 38 39fun try f x = f x handle e => Feedback.Raise e 40 41fun assert P x = assert_exn P x (ERR "assert" "predicate not true") 42 43(*---------------------------------------------------------------------------* 44 * Common list operations * 45 *---------------------------------------------------------------------------*) 46 47(* turning lists into tuples *) 48 49fun singleton_of_list [x] = x 50 | singleton_of_list _ = raise ERR "singleton_of_list" "not a list of length 1" 51 52fun pair_of_list [x, y] = (x, y) 53 | pair_of_list _ = raise ERR "pair_of_list" "not a list of length 2" 54 55fun triple_of_list [x, y, z] = (x, y, z) 56 | triple_of_list _ = raise ERR "triple_of_list" "not a list of length 3" 57 58fun quadruple_of_list [x1, x2, x3, x4] = (x1, x2, x3, x4) 59 | quadruple_of_list _ = raise ERR "quadruple_of_list" "not a list of length 4" 60 61fun tryfind f = 62 let 63 fun F [] = raise ERR "tryfind" "all applications failed" 64 | F (h :: t) = f h handle Interrupt => raise Interrupt | _ => F t 65 in 66 F 67 end 68 69(* Counting starts from 1 *) 70 71fun el n l = 72 if n < 1 73 then raise ERR "el" "index too small" 74 else let 75 fun elem (_, []) = raise ERR "el" "index too large" 76 | elem (1, h :: _) = h 77 | elem (n, _ :: rst) = elem (n - 1, rst) 78 in 79 elem (n, l) 80 end 81 82fun index P l = 83 let 84 fun idx (i, []) = raise ERR "index" "no such element" 85 | idx (i, y :: l) = if P y then i else idx (i + 1, l) 86 in 87 idx (0, l) 88 end 89 90fun map2 f L1 L2 = 91 let 92 fun mp2 [] [] L = rev L 93 | mp2 (a1 :: rst1) (a2 :: rst2) L = mp2 rst1 rst2 (f a1 a2 :: L) 94 | mp2 _ _ _ = raise ERR "map2" "different length lists" 95 in 96 mp2 L1 L2 [] 97 end 98 99fun all2 P = 100 let 101 fun every2 [] [] = true 102 | every2 (a1 :: rst1) (a2 :: rst2) = P a1 a2 andalso every2 rst1 rst2 103 | every2 _ _ = raise ERR "all2" "different length lists" 104 in 105 every2 106 end 107 108fun first P = 109 let 110 fun oneth (a :: rst) = if P a then a else oneth rst 111 | oneth [] = raise ERR "first" "unsatisfied predicate" 112 in 113 oneth 114 end 115 116fun split_after n alist = 117 if n >= 0 118 then let 119 fun spa 0 (L, R) = (rev L, R) 120 | spa n (L, a :: rst) = spa (n - 1) (a :: L, rst) 121 | spa _ _ = raise ERR "split_after" "index too big" 122 in 123 spa n ([], alist) 124 end 125 else raise ERR "split_after" "negative index" 126 127fun itlist2 f L1 L2 base_value = 128 let 129 fun itl ([], []) = base_value 130 | itl (a :: rst1, b :: rst2) = f a b (itl (rst1, rst2)) 131 | itl _ = raise ERR "itlist2" "lists of different length" 132 in 133 itl (L1, L2) 134 end 135 136fun rev_itlist2 f L1 L2 = 137 let 138 fun rev_it2 ([], []) base = base 139 | rev_it2 (a :: rst1, b :: rst2) base = rev_it2 (rst1, rst2) (f a b base) 140 | rev_it2 _ _ = raise ERR"rev_itlist2" "lists of different length" 141 in 142 rev_it2 (L1, L2) 143 end 144 145fun end_itlist f = 146 let 147 fun endit [] = raise ERR "end_itlist" "list too short" 148 | endit [x] = x 149 | endit (h :: t) = f h (endit t) 150 in 151 endit 152 end 153 154fun get_first f l = 155 case l of 156 [] => NONE 157 | h :: t => (case f h of NONE => get_first f t | some => some) 158 159fun zip [] [] = [] 160 | zip (a :: b) (c :: d) = (a, c) :: zip b d 161 | zip _ _ = raise ERR "zip" "different length lists" 162 163fun combine (l1, l2) = zip l1 l2 164 165fun butlast l = 166 fst (front_last l) handle HOL_ERR _ => raise ERR "butlast" "empty list" 167 168fun last [] = raise ERR "last" "empty list" 169 | last [x] = x 170 | last (_ :: t) = last t 171 172fun pluck P = 173 let 174 fun pl _ [] = raise ERR "pluck" "predicate not satisfied" 175 | pl A (h :: t) = 176 if P h then (h, List.revAppend (A, t)) else pl (h :: A) t 177 in 178 pl [] 179 end 180 181fun trypluck f = 182 let 183 fun try acc [] = raise ERR "trypluck" "no successful fn. application" 184 | try acc (h :: t) = 185 case total f h of 186 NONE => try (h :: acc) t 187 | SOME v => (v, List.revAppend (acc, t)) 188 in 189 try [] 190 end 191 192(* apnth : ('a -> 'a) -> int -> 'a list -> 'a list 193 apply a function to the nth member of a list *) 194fun apnth f 0 (y :: ys) = f y :: ys 195 | apnth f n (y :: ys) = y :: apnth f (n-1) ys 196 | apnth f n [] = raise ERR "apnth" "list too short (or -ve index)" 197 198fun mapshape [] _ _ = [] 199 | mapshape (n :: nums) (f :: funcs) all_args = 200 let 201 val (fargs, rst) = split_after n all_args 202 in 203 f fargs :: mapshape nums funcs rst 204 end 205 | mapshape _ _ _ = raise ERR "mapshape" "irregular lists" 206 207(*---------------------------------------------------------------------------* 208 * Assoc lists. * 209 *---------------------------------------------------------------------------*) 210 211fun assoc item = 212 let 213 fun assc ((key, ob) :: rst) = if item = key then ob else assc rst 214 | assc [] = raise ERR "assoc" "not found" 215 in 216 assc 217 end 218 219fun rev_assoc item = 220 let 221 fun assc ((ob, key) :: rst) = if item = key then ob else assc rst 222 | assc [] = raise ERR "assoc" "not found" 223 in 224 assc 225 end 226 227fun op_assoc eq_func k l = 228 case l of 229 [] => raise ERR "op_assoc" "not found" 230 | (key,ob) :: rst => if eq_func k key then ob else op_assoc eq_func k rst 231 232fun op_rev_assoc eq_func k l = 233 case l of 234 [] => raise ERR "op_rev_assoc" "not found" 235 | (ob,key) :: rest => if eq_func k key then ob 236 else op_rev_assoc eq_func k rest 237 238(*---------------------------------------------------------------------------*) 239(* Topologically sort a list wrt partial order R. *) 240(*---------------------------------------------------------------------------*) 241 242fun topsort R = 243 let 244 fun pred_of y x = R x y 245 fun a1 l1 l2 = l1 @ l2 246 fun a2 l1 l2 = foldl (op ::) l2 l1 247 fun deps [] _ acc = acc 248 | deps (h :: t) front (nodeps, rst) = 249 let 250 val pred_of_h = pred_of h 251 val hdep = exists pred_of_h t orelse exists pred_of_h front 252 val acc = if hdep then (nodeps, h :: rst) else (h :: nodeps, rst) 253 in 254 deps t (h :: front) acc 255 end 256 fun loop _ [] = [] 257 | loop (a1, a2) l = 258 case (deps l [] ([], [])) of 259 ([], _) => raise ERR "topsort" "cyclic dependency" 260 | (nodeps, rst) => a1 nodeps (loop (a2, a1) rst) 261 in 262 loop (a2, a1) 263 end 264 265(* for the following two implementations, 266 each node appears before all its dependencies 267 in the returned list *) 268 269(* O(n*log(n)) time version 270 deps = map from nodes to adjacency lists *) 271 272fun dict_topsort deps = 273 let 274 open Redblackmap 275 val deps = transform (fn ls => ref (SOME ls)) deps 276 fun visit (n, ls) = 277 let 278 val r = find (deps, n) 279 in 280 case !r of 281 NONE => ls 282 | SOME dl => let 283 val _ = r := NONE 284 val ls = List.foldl visit ls dl 285 in 286 n :: ls 287 end 288 end 289 fun v (n, _, ls) = visit (n, ls) 290 in 291 foldl v [] deps 292 end 293 294(*---------------------------------------------------------------------------* 295 * Strings. * 296 *---------------------------------------------------------------------------*) 297 298val string_to_int = 299 partial (ERR "string_to_int" "not convertable") Int.fromString 300 301val saying = ref true 302 303fun say s = if !saying then !Feedback.MESG_outstream s else () 304 305fun unprime s = 306 let 307 val n = size s - 1 308 in 309 if 0 <= n andalso String.sub (s, n) = #"'" 310 then String.substring (s, 0, n) 311 else raise ERR "unprime" "string doesn't end with a prime" 312 end 313 314fun extract_pc s = 315 let 316 (* c = # of primes seen; 317 i = current index into string, terminate on -1 318 -- does right thing on UTF8 encoded codepoints 319 *) 320 fun recurse c i = 321 if i < 0 then ("", c) 322 else if String.sub(s,i) = #"'" then recurse (c + 1) (i - 1) 323 else (String.substring(s,0,i+1), c) 324 in 325 recurse 0 (String.size s - 1) 326 end 327 328 329fun unprefix pfx s = 330 if String.isPrefix pfx s 331 then String.extract (s, size pfx, NONE) 332 else raise ERR "unprefix" "1st argument is not a prefix of 2nd argument" 333 334fun ppstring pf x = HOLPP.pp_to_string (!Globals.linewidth) pf x 335 336fun delete_trailing_wspace s = 337 let 338 val toks = String.fields (equal #"\n") s 339 fun do1 i s = 340 if i < 0 then "" 341 else if Char.isSpace (String.sub(s,i)) then do1 (i - 1) s 342 else String.extract(s,0,SOME(i + 1)) 343 fun remove_rptd_nls i cnt s = 344 if i < 0 then if cnt > 0 then "\n" else "" 345 else if String.sub(s,i) = #"\n" then 346 remove_rptd_nls (i - 1) (cnt + 1) s 347 else String.extract(s,0,SOME(i + 1 + (if cnt > 0 then 1 else 0))) 348 val s1 = String.concatWith "\n" (map (fn s => do1 (size s - 1) s) toks) 349 in 350 remove_rptd_nls (size s1 - 1) 0 s1 351 end 352 353(*---------------------------------------------------------------------------* 354 * Timing * 355 *---------------------------------------------------------------------------*) 356 357local 358 val second = Time.fromReal 1.0 359 val minute = Time.fromReal 60.0 360 val year0 = Date.year (Date.fromTimeUniv Time.zeroTime) 361 fun to_str i u = if i = 0 then "" else Int.toString i ^ u 362in 363 fun time_to_string t = 364 if Time.< (t, second) 365 then Time.fmt 5 t ^ "s" 366 else if Time.< (t, minute) 367 then Time.fmt 1 t ^ "s" 368 else let 369 val d = Date.fromTimeUniv t 370 val years = Date.year d - year0 371 val days = Date.yearDay d 372 val hours = Date.hour d 373 val minutes = Date.minute d 374 in 375 if years + days + hours = 0 andalso minutes < 10 then 376 to_str minutes "m" ^ Date.fmt "%Ss" d 377 else to_str years "y" ^ to_str days "d" ^ to_str hours "h" ^ 378 Date.fmt "%Mm%Ss" d 379 end 380end 381 382fun start_time () = Timer.startCPUTimer () 383 384fun end_time timer = 385 let 386 val {sys, usr} = Timer.checkCPUTimer timer 387 val gc = Timer.checkGCTime timer 388 in 389 say ("runtime: " ^ time_to_string usr ^ ",\ 390 \ gctime: " ^ time_to_string gc ^ ", \ 391 \ systime: " ^ time_to_string sys ^ ".\n") 392 end 393 394fun time f x = 395 let 396 val timer = start_time () 397 val y = f x handle e => (end_time timer; raise e) 398 in 399 end_time timer; y 400 end 401 402fun start_real_time () = Timer.startRealTimer () 403 404fun end_real_time timer = 405 say ("realtime: " ^ Time.toString (Timer.checkRealTimer timer) ^ "s\n") 406 407fun real_time f x = 408 let 409 val timer = start_real_time () 410 val y = f x handle e => (end_real_time timer; raise e) 411 in 412 end_real_time timer; y 413 end 414 415(* set helpers/abbreviations *) 416type 'a set = 'a HOLset.set 417fun op Un p = HOLset.union p 418fun op Isct p = HOLset.intersection p 419fun op -- p = HOLset.difference p 420fun op IN (e,s) = HOLset.member(s,e) 421 422(* more equality function functions *) 423fun subst_eq aeq beq = list_eq (redres_eq aeq beq) 424 425end (* Lib *) 426