2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
4 \section[Util]{Highly random utility functions}
7 #if defined(COMPILING_GHC)
8 # include "HsVersions.h"
9 # define IF_NOT_GHC(a) {--}
12 # define TAG_ _CMP_TAG
17 # define tagCmp_ _tagCmp
18 # define FAST_STRING String
19 # define ASSERT(x) {-nothing-}
20 # define IF_NOT_GHC(a) a
24 #ifndef __GLASGOW_HASKELL__
33 -- Haskell-version support
34 #ifndef __GLASGOW_HASKELL__
38 -- general list processing
39 IF_NOT_GHC(forall COMMA exists COMMA)
40 zipEqual, zipWithEqual, zipWith3Equal, zipWith4Equal,
42 nOfThem, lengthExceeds, isSingleton,
44 #if defined(COMPILING_GHC)
52 hasNoDups, equivClasses, runs, removeDups,
55 IF_NOT_GHC(quicksort COMMA stableSortLt COMMA mergesort COMMA)
57 IF_NOT_GHC(mergeSort COMMA) naturalMergeSortLe, -- from Carsten
58 IF_NOT_GHC(naturalMergeSort COMMA mergeSortLe COMMA)
60 -- transitive closures
64 mapAccumL, mapAccumR, mapAccumB,
67 Ord3(..), thenCmp, cmpList,
68 IF_NOT_GHC(cmpString COMMA)
69 #ifdef USE_FAST_STRINGS
75 IF_NOT_GHC(cfst COMMA applyToPair COMMA applyToFst COMMA)
76 IF_NOT_GHC(applyToSnd COMMA foldPair COMMA)
80 #if defined(COMPILING_GHC)
81 , panic, panic#, pprPanic, pprPanic#, pprError, pprTrace
85 #endif {- COMPILING_GHC -}
87 -- and to make the interface self-sufficient...
89 # if defined(COMPILING_GHC)
90 , Maybe(..){-.. for pragmas...-}, PrettyRep, Pretty(..)
98 #if defined(COMPILING_GHC)
100 CHK_Ubiq() -- debugging consistency check
105 import Maybes ( Maybe(..) )
109 %************************************************************************
111 \subsection[Utils-version-support]{Functions to help pre-1.2 versions of (non-Glasgow) Haskell}
113 %************************************************************************
115 This is our own idea:
117 #ifndef __GLASGOW_HASKELL__
118 data TAG_ = LT_ | EQ_ | GT_
120 tagCmp_ :: Ord a => a -> a -> TAG_
121 tagCmp_ a b = if a == b then EQ_ else if a < b then LT_ else GT_
125 %************************************************************************
127 \subsection[Utils-lists]{General list processing}
129 %************************************************************************
131 Quantifiers are not standard in Haskell. The following fill in the gap.
134 forall :: (a -> Bool) -> [a] -> Bool
135 forall pred [] = True
136 forall pred (x:xs) = pred x && forall pred xs
138 exists :: (a -> Bool) -> [a] -> Bool
139 exists pred [] = False
140 exists pred (x:xs) = pred x || exists pred xs
143 A paranoid @zip@ (and some @zipWith@ friends) that checks the lists
144 are of equal length. Alastair Reid thinks this should only happen if
145 DEBUGging on; hey, why not?
148 zipEqual :: [a] -> [b] -> [(a,b)]
149 zipWithEqual :: (a->b->c) -> [a]->[b]->[c]
150 zipWith3Equal :: (a->b->c->d) -> [a]->[b]->[c]->[d]
151 zipWith4Equal :: (a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e]
155 zipWithEqual = zipWith
156 zipWith3Equal = zipWith3
157 zipWith4Equal = zipWith4
160 zipEqual (a:as) (b:bs) = (a,b) : zipEqual as bs
161 zipEqual as bs = panic "zipEqual: unequal lists"
163 zipWithEqual z (a:as) (b:bs) = z a b : zipWithEqual z as bs
164 zipWithEqual _ [] [] = []
165 zipWithEqual _ _ _ = panic "zipWithEqual: unequal lists"
167 zipWith3Equal z (a:as) (b:bs) (c:cs)
168 = z a b c : zipWith3Equal z as bs cs
169 zipWith3Equal _ [] [] [] = []
170 zipWith3Equal _ _ _ _ = panic "zipWith3Equal: unequal lists"
172 zipWith4Equal z (a:as) (b:bs) (c:cs) (d:ds)
173 = z a b c d : zipWith4Equal z as bs cs ds
174 zipWith4Equal _ [] [] [] [] = []
175 zipWith4Equal _ _ _ _ _ = panic "zipWith4Equal: unequal lists"
180 -- zipLazy is lazy in the second list (observe the ~)
182 zipLazy :: [a] -> [b] -> [(a,b)]
184 zipLazy (x:xs) ~(y:ys) = (x,y) : zipLazy xs ys
188 nOfThem :: Int -> a -> [a]
189 nOfThem n thing = take n (repeat thing)
191 lengthExceeds :: [a] -> Int -> Bool
193 [] `lengthExceeds` n = 0 > n
194 (x:xs) `lengthExceeds` n = (1 > n) || (xs `lengthExceeds` (n - 1))
196 isSingleton :: [a] -> Bool
198 isSingleton [x] = True
199 isSingleton _ = False
201 startsWith, endsWith :: String -> String -> Maybe String
203 startsWith [] str = Just str
204 startsWith (c:cs) (s:ss)
205 = if c /= s then Nothing else startsWith cs ss
208 = case (startsWith (reverse cs) (reverse ss)) of
210 Just rs -> Just (reverse rs)
213 Debugging/specialising versions of \tr{elem} and \tr{notElem}
215 #if defined(COMPILING_GHC)
216 isIn, isn'tIn :: (Eq a) => String -> a -> [a] -> Bool
219 isIn msg x ys = elem__ x ys
220 isn'tIn msg x ys = notElem__ x ys
222 --these are here to be SPECIALIZEd (automagically)
224 elem__ x (y:ys) = x==y || elem__ x ys
226 notElem__ x [] = True
227 notElem__ x (y:ys) = x /= y && notElem__ x ys
235 | i _GE_ ILIT(100) = panic ("Over-long elem in: " ++ msg)
236 | otherwise = x == y || elem (i _ADD_ ILIT(1)) x ys
239 = notElem ILIT(0) x ys
241 notElem i x [] = True
243 | i _GE_ ILIT(100) = panic ("Over-long notElem in: " ++ msg)
244 | otherwise = x /= y && notElem (i _ADD_ ILIT(1)) x ys
248 # ifdef USE_ATTACK_PRAGMAS
249 {-# SPECIALIZE isIn :: String -> Literal -> [Literal] -> Bool #-}
250 {-# SPECIALIZE isIn :: String -> Class -> [Class] -> Bool #-}
251 {-# SPECIALIZE isIn :: String -> Id -> [Id] -> Bool #-}
252 {-# SPECIALIZE isIn :: String -> Int -> [Int] -> Bool #-}
253 {-# SPECIALIZE isIn :: String -> MagicId -> [MagicId] -> Bool #-}
254 {-# SPECIALIZE isIn :: String -> Name -> [Name] -> Bool #-}
255 {-# SPECIALIZE isIn :: String -> TyCon -> [TyCon] -> Bool #-}
256 {-# SPECIALIZE isIn :: String -> TyVar -> [TyVar] -> Bool #-}
257 {-# SPECIALIZE isIn :: String -> TyVarTemplate -> [TyVarTemplate] -> Bool #-}
258 {-# SPECIALIZE isIn :: String -> Unique -> [Unique] -> Bool #-}
259 {-# SPECIALIZE isIn :: String -> _PackedString -> [_PackedString] -> Bool #-}
260 {-# SPECIALIZE isn'tIn :: String -> (Id, Id) -> [(Id, Id)] -> Bool #-}
261 {-# SPECIALIZE isn'tIn :: String -> Int -> [Int] -> Bool #-}
262 {-# SPECIALIZE isn'tIn :: String -> Id -> [Id] -> Bool #-}
263 {-# SPECIALIZE isn'tIn :: String -> MagicId -> [MagicId] -> Bool #-}
264 {-# SPECIALIZE isn'tIn :: String -> TyCon -> [TyCon] -> Bool #-}
265 {-# SPECIALIZE isn'tIn :: String -> TyVar -> [TyVar] -> Bool #-}
266 {-# SPECIALIZE isn'tIn :: String -> TyVarTemplate -> [TyVarTemplate] -> Bool #-}
269 #endif {- COMPILING_GHC -}
272 %************************************************************************
274 \subsection[Utils-assoc]{Association lists}
276 %************************************************************************
278 See also @assocMaybe@ and @mkLookupFun@ in module @Maybes@.
281 assoc :: (Eq a) => String -> [(a, b)] -> a -> b
283 assoc crash_msg lst key
285 then panic ("Failed in assoc: " ++ crash_msg)
287 where res = [ val | (key', val) <- lst, key == key']
289 #if defined(COMPILING_GHC)
290 # ifdef USE_ATTACK_PRAGMAS
291 {-# SPECIALIZE assoc :: String -> [(Id, a)] -> Id -> a #-}
292 {-# SPECIALIZE assoc :: String -> [(Class, a)] -> Class -> a #-}
293 {-# SPECIALIZE assoc :: String -> [(Name, a)] -> Name -> a #-}
294 {-# SPECIALIZE assoc :: String -> [(PrimRep, a)] -> PrimRep -> a #-}
295 {-# SPECIALIZE assoc :: String -> [(String, a)] -> String -> a #-}
296 {-# SPECIALIZE assoc :: String -> [(TyCon, a)] -> TyCon -> a #-}
297 {-# SPECIALIZE assoc :: String -> [(TyVar, a)] -> TyVar -> a #-}
298 {-# SPECIALIZE assoc :: String -> [(TyVarTemplate, a)] -> TyVarTemplate -> a #-}
299 {-# SPECIALIZE assoc :: String -> [(Type, a)] -> Type -> a #-}
300 {-# SPECIALIZE assoc :: String -> [(_PackedString, a)] -> _PackedString -> a #-}
305 %************************************************************************
307 \subsection[Utils-dups]{Duplicate-handling}
309 %************************************************************************
312 hasNoDups :: (Eq a) => [a] -> Bool
314 hasNoDups xs = f [] xs
316 f seen_so_far [] = True
317 f seen_so_far (x:xs) = if x `is_elem` seen_so_far then
322 #if defined(COMPILING_GHC)
323 is_elem = isIn "hasNoDups"
327 #if defined(COMPILING_GHC)
328 # ifdef USE_ATTACK_PRAGMAS
329 {-# SPECIALIZE hasNoDups :: [TyVar] -> Bool #-}
335 equivClasses :: (a -> a -> TAG_) -- Comparison
339 equivClasses cmp stuff@[] = []
340 equivClasses cmp stuff@[item] = [stuff]
341 equivClasses cmp items
342 = runs eq (sortLt lt items)
344 eq a b = case cmp a b of { EQ_ -> True; _ -> False }
345 lt a b = case cmp a b of { LT_ -> True; _ -> False }
348 The first cases in @equivClasses@ above are just to cut to the point
351 @runs@ groups a list into a list of lists, each sublist being a run of
352 identical elements of the input list. It is passed a predicate @p@ which
353 tells when two elements are equal.
356 runs :: (a -> a -> Bool) -- Equality
361 runs p (x:xs) = case (span (p x) xs) of
362 (first, rest) -> (x:first) : (runs p rest)
366 removeDups :: (a -> a -> TAG_) -- Comparison function
368 -> ([a], -- List with no duplicates
369 [[a]]) -- List of duplicate groups. One representative from
370 -- each group appears in the first result
372 removeDups cmp [] = ([], [])
373 removeDups cmp [x] = ([x],[])
375 = case (mapAccumR collect_dups [] (equivClasses cmp xs)) of { (dups, xs') ->
378 collect_dups dups_so_far [x] = (dups_so_far, x)
379 collect_dups dups_so_far dups@(x:xs) = (dups:dups_so_far, x)
382 %************************************************************************
384 \subsection[Utils-sorting]{Sorting}
386 %************************************************************************
388 %************************************************************************
390 \subsubsection[Utils-quicksorting]{Quicksorts}
392 %************************************************************************
395 -- tail-recursive, etc., "quicker sort" [as per Meira thesis]
396 quicksort :: (a -> a -> Bool) -- Less-than predicate
398 -> [a] -- Result list in increasing order
401 quicksort lt [x] = [x]
402 quicksort lt (x:xs) = split x [] [] xs
404 split x lo hi [] = quicksort lt lo ++ (x : quicksort lt hi)
405 split x lo hi (y:ys) | y `lt` x = split x (y:lo) hi ys
406 | True = split x lo (y:hi) ys
409 Quicksort variant from Lennart's Haskell-library contribution. This
410 is a {\em stable} sort.
413 stableSortLt = sortLt -- synonym; when we want to highlight stable-ness
415 sortLt :: (a -> a -> Bool) -- Less-than predicate
417 -> [a] -- Result list
419 sortLt lt l = qsort lt l []
421 -- qsort is stable and does not concatenate.
422 qsort :: (a -> a -> Bool) -- Less-than predicate
423 -> [a] -- xs, Input list
424 -> [a] -- r, Concatenate this list to the sorted input list
425 -> [a] -- Result = sort xs ++ r
429 qsort lt (x:xs) r = qpart lt x xs [] [] r
431 -- qpart partitions and sorts the sublists
432 -- rlt contains things less than x,
433 -- rge contains the ones greater than or equal to x.
434 -- Both have equal elements reversed with respect to the original list.
436 qpart lt x [] rlt rge r =
437 -- rlt and rge are in reverse order and must be sorted with an
438 -- anti-stable sorting
439 rqsort lt rlt (x : rqsort lt rge r)
441 qpart lt x (y:ys) rlt rge r =
444 qpart lt x ys (y:rlt) rge r
447 qpart lt x ys rlt (y:rge) r
449 -- rqsort is as qsort but anti-stable, i.e. reverses equal elements
451 rqsort lt [x] r = x:r
452 rqsort lt (x:xs) r = rqpart lt x xs [] [] r
454 rqpart lt x [] rle rgt r =
455 qsort lt rle (x : qsort lt rgt r)
457 rqpart lt x (y:ys) rle rgt r =
460 rqpart lt x ys rle (y:rgt) r
463 rqpart lt x ys (y:rle) rgt r
466 %************************************************************************
468 \subsubsection[Utils-dull-mergesort]{A rather dull mergesort}
470 %************************************************************************
473 mergesort :: (a -> a -> TAG_) -> [a] -> [a]
475 mergesort cmp xs = merge_lists (split_into_runs [] xs)
477 a `le` b = case cmp a b of { LT_ -> True; EQ_ -> True; GT__ -> False }
478 a `ge` b = case cmp a b of { LT_ -> False; EQ_ -> True; GT__ -> True }
480 split_into_runs [] [] = []
481 split_into_runs run [] = [run]
482 split_into_runs [] (x:xs) = split_into_runs [x] xs
483 split_into_runs [r] (x:xs) | x `ge` r = split_into_runs [r,x] xs
484 split_into_runs rl@(r:rs) (x:xs) | x `le` r = split_into_runs (x:rl) xs
485 | True = rl : (split_into_runs [x] xs)
488 merge_lists (x:xs) = merge x (merge_lists xs)
492 merge xl@(x:xs) yl@(y:ys)
494 EQ_ -> x : y : (merge xs ys)
495 LT_ -> x : (merge xs yl)
496 GT__ -> y : (merge xl ys)
499 %************************************************************************
501 \subsubsection[Utils-Carsten-mergesort]{A mergesort from Carsten}
503 %************************************************************************
506 Date: Mon, 3 May 93 20:45:23 +0200
507 From: Carsten Kehler Holst <kehler@cs.chalmers.se>
508 To: partain@dcs.gla.ac.uk
509 Subject: natural merge sort beats quick sort [ and it is prettier ]
511 Here is a piece of Haskell code that I'm rather fond of. See it as an
512 attempt to get rid of the ridiculous quick-sort routine. group is
513 quite useful by itself I think it was John's idea originally though I
514 believe the lazy version is due to me [surprisingly complicated].
515 gamma [used to be called] is called gamma because I got inspired by
516 the Gamma calculus. It is not very close to the calculus but does
517 behave less sequentially than both foldr and foldl. One could imagine
518 a version of gamma that took a unit element as well thereby avoiding
519 the problem with empty lists.
521 I've tried this code against
523 1) insertion sort - as provided by haskell
524 2) the normal implementation of quick sort
525 3) a deforested version of quick sort due to Jan Sparud
526 4) a super-optimized-quick-sort of Lennart's
528 If the list is partially sorted both merge sort and in particular
529 natural merge sort wins. If the list is random [ average length of
530 rising subsequences = approx 2 ] mergesort still wins and natural
531 merge sort is marginally beaten by Lennart's soqs. The space
532 consumption of merge sort is a bit worse than Lennart's quick sort
533 approx a factor of 2. And a lot worse if Sparud's bug-fix [see his
534 fpca article ] isn't used because of group.
541 group :: (a -> a -> Bool) -> [a] -> [[a]]
544 Date: Mon, 12 Feb 1996 15:09:41 +0000
545 From: Andy Gill <andy@dcs.gla.ac.uk>
547 Here is a `better' definition of group.
550 group p (x:xs) = group' xs x x (x :)
552 group' [] _ _ s = [s []]
553 group' (x:xs) x_min x_max s
554 | not (x `p` x_max) = group' xs x_min x (s . (x :))
555 | x `p` x_min = group' xs x x_max ((x :) . s)
556 | otherwise = s [] : group' xs x x (x :)
558 -- This one works forwards *and* backwards, as well as also being
559 -- faster that the one in Util.lhs.
564 let ((h1:t1):tt1) = group p xs
565 (t,tt) = if null xs then ([],[]) else
566 if x `p` h1 then (h1:t1,tt1) else
571 generalMerge :: (a -> a -> Bool) -> [a] -> [a] -> [a]
572 generalMerge p xs [] = xs
573 generalMerge p [] ys = ys
574 generalMerge p (x:xs) (y:ys) | x `p` y = x : generalMerge p xs (y:ys)
575 | otherwise = y : generalMerge p (x:xs) ys
577 -- gamma is now called balancedFold
579 balancedFold :: (a -> a -> a) -> [a] -> a
580 balancedFold f [] = error "can't reduce an empty list using balancedFold"
581 balancedFold f [x] = x
582 balancedFold f l = balancedFold f (balancedFold' f l)
584 balancedFold' :: (a -> a -> a) -> [a] -> [a]
585 balancedFold' f (x:y:xs) = f x y : balancedFold' f xs
586 balancedFold' f xs = xs
588 generalMergeSort p [] = []
589 generalMergeSort p xs = (balancedFold (generalMerge p) . map (: [])) xs
591 generalNaturalMergeSort p [] = []
592 generalNaturalMergeSort p xs = (balancedFold (generalMerge p) . group p) xs
594 mergeSort, naturalMergeSort :: Ord a => [a] -> [a]
596 mergeSort = generalMergeSort (<=)
597 naturalMergeSort = generalNaturalMergeSort (<=)
599 mergeSortLe le = generalMergeSort le
600 naturalMergeSortLe le = generalNaturalMergeSort le
603 %************************************************************************
605 \subsection[Utils-transitive-closure]{Transitive closure}
607 %************************************************************************
609 This algorithm for transitive closure is straightforward, albeit quadratic.
612 transitiveClosure :: (a -> [a]) -- Successor function
613 -> (a -> a -> Bool) -- Equality predicate
615 -> [a] -- The transitive closure
617 transitiveClosure succ eq xs
621 do done (x:xs) | x `is_in` done = do done xs
622 | otherwise = do (x:done) (succ x ++ xs)
625 x `is_in` (y:ys) | eq x y = True
626 | otherwise = x `is_in` ys
629 %************************************************************************
631 \subsection[Utils-accum]{Accumulating}
633 %************************************************************************
635 @mapAccumL@ behaves like a combination
636 of @map@ and @foldl@;
637 it applies a function to each element of a list, passing an accumulating
638 parameter from left to right, and returning a final value of this
639 accumulator together with the new list.
642 mapAccumL :: (acc -> x -> (acc, y)) -- Function of elt of input list
643 -- and accumulator, returning new
644 -- accumulator and elt of result list
645 -> acc -- Initial accumulator
647 -> (acc, [y]) -- Final accumulator and result list
649 mapAccumL f b [] = (b, [])
650 mapAccumL f b (x:xs) = (b'', x':xs') where
652 (b'', xs') = mapAccumL f b' xs
655 @mapAccumR@ does the same, but working from right to left instead. Its type is
656 the same as @mapAccumL@, though.
659 mapAccumR :: (acc -> x -> (acc, y)) -- Function of elt of input list
660 -- and accumulator, returning new
661 -- accumulator and elt of result list
662 -> acc -- Initial accumulator
664 -> (acc, [y]) -- Final accumulator and result list
666 mapAccumR f b [] = (b, [])
667 mapAccumR f b (x:xs) = (b'', x':xs') where
669 (b', xs') = mapAccumR f b xs
672 Here is the bi-directional version, that works from both left and right.
675 mapAccumB :: (accl -> accr -> x -> (accl, accr,y))
676 -- Function of elt of input list
677 -- and accumulator, returning new
678 -- accumulator and elt of result list
679 -> accl -- Initial accumulator from left
680 -> accr -- Initial accumulator from right
682 -> (accl, accr, [y]) -- Final accumulators and result list
684 mapAccumB f a b [] = (a,b,[])
685 mapAccumB f a b (x:xs) = (a'',b'',y:ys)
687 (a',b'',y) = f a b' x
688 (a'',b',ys) = mapAccumB f a' b xs
691 %************************************************************************
693 \subsection[Utils-comparison]{Comparisons}
695 %************************************************************************
697 See also @tagCmp_@ near the versions-compatibility section.
699 The Ord3 class will be subsumed into Ord in Haskell 1.3.
703 cmp :: a -> a -> TAG_
705 thenCmp :: TAG_ -> TAG_ -> TAG_
706 {-# INLINE thenCmp #-}
707 thenCmp EQ_ any = any
708 thenCmp other any = other
710 cmpList :: (a -> a -> TAG_) -> [a] -> [a] -> TAG_
711 -- `cmpList' uses a user-specified comparer
713 cmpList cmp [] [] = EQ_
714 cmpList cmp [] _ = LT_
715 cmpList cmp _ [] = GT_
716 cmpList cmp (a:as) (b:bs)
717 = case cmp a b of { EQ_ -> cmpList cmp as bs; xxx -> xxx }
721 instance Ord3 a => Ord3 [a] where
725 cmp (x:xs) (y:ys) = (x `cmp` y) `thenCmp` (xs `cmp` ys)
727 instance Ord3 a => Ord3 (Maybe a) where
728 cmp Nothing Nothing = EQ_
729 cmp Nothing (Just y) = LT_
730 cmp (Just x) Nothing = GT_
731 cmp (Just x) (Just y) = x `cmp` y
733 instance Ord3 Int where
734 cmp a b | a < b = LT_
740 cmpString :: String -> String -> TAG_
742 cmpString [] [] = EQ_
743 cmpString (x:xs) (y:ys) = if x == y then cmpString xs ys
744 else if x < y then LT_
746 cmpString [] ys = LT_
747 cmpString xs [] = GT_
749 cmpString _ _ = panic# "cmpString"
753 #ifdef USE_FAST_STRINGS
754 cmpPString :: FAST_STRING -> FAST_STRING -> TAG_
757 = case (_tagCmp x y) of { _LT -> LT_ ; _EQ -> EQ_ ; _GT -> GT_ }
762 #ifndef USE_FAST_STRINGS
763 substr :: FAST_STRING -> Int -> Int -> FAST_STRING
766 = ASSERT (beg >= 0 && beg <= end)
767 take (end - beg + 1) (drop beg str)
771 %************************************************************************
773 \subsection[Utils-pairs]{Pairs}
775 %************************************************************************
777 The following are curried versions of @fst@ and @snd@.
780 cfst :: a -> b -> a -- stranal-sem only (Note)
784 The following provide us higher order functions that, when applied
785 to a function, operate on pairs.
788 applyToPair :: ((a -> c),(b -> d)) -> (a,b) -> (c,d)
789 applyToPair (f,g) (x,y) = (f x, g y)
791 applyToFst :: (a -> c) -> (a,b)-> (c,b)
792 applyToFst f (x,y) = (f x,y)
794 applyToSnd :: (b -> d) -> (a,b) -> (a,d)
795 applyToSnd f (x,y) = (x,f y)
797 foldPair :: (a->a->a,b->b->b) -> (a,b) -> [(a,b)] -> (a,b)
798 foldPair fg ab [] = ab
799 foldPair fg@(f,g) ab ((a,b):abs) = (f a u,g b v)
800 where (u,v) = foldPair fg ab abs
804 unzipWith :: (a -> b -> c) -> [(a, b)] -> [c]
805 unzipWith f pairs = map ( \ (a, b) -> f a b ) pairs
808 %************************************************************************
810 \subsection[Utils-errors]{Error handling}
812 %************************************************************************
815 #if defined(COMPILING_GHC)
816 panic x = error ("panic! (the `impossible' happened):\n\t"
818 ++ "Please report it as a compiler bug "
819 ++ "to glasgow-haskell-bugs@dcs.glasgow.ac.uk.\n\n" )
821 pprPanic heading pretty_msg = panic (heading++(ppShow 80 pretty_msg))
822 pprError heading pretty_msg = error (heading++(ppShow 80 pretty_msg))
823 pprTrace heading pretty_msg = trace (heading++(ppShow 80 pretty_msg))
825 -- #-versions because panic can't return an unboxed int, and that's
826 -- what TAG_ is with GHC at the moment. Ugh. (Simon)
827 -- No, man -- Too Beautiful! (Will)
829 panic# :: String -> TAG_
830 panic# s = case (panic s) of () -> EQ_
832 pprPanic# heading pretty_msg = panic# (heading++(ppShow 80 pretty_msg))
835 assertPanic :: String -> Int -> a
836 assertPanic file line = panic ("ASSERT failed! file "++file++", line "++show line)
838 #endif {- COMPILING_GHC -}