PageRenderTime 25ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/ghc-7.0.4/compiler/utils/ListSetOps.lhs

http://picorec.googlecode.com/
Haskell | 224 lines | 165 code | 45 blank | 14 comment | 6 complexity | 314cf098be95572713f5a04ec45ee822 MD5 | raw file
Possible License(s): BSD-3-Clause, BSD-2-Clause
  1. %
  2. % (c) The University of Glasgow 2006
  3. % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
  4. %
  5. \section[ListSetOps]{Set-like operations on lists}
  6. \begin{code}
  7. module ListSetOps (
  8. unionLists, minusList, insertList,
  9. -- Association lists
  10. Assoc, assoc, assocMaybe, assocUsing, assocDefault, assocDefaultUsing,
  11. emptyAssoc, unitAssoc, mapAssoc, plusAssoc_C, extendAssoc_C,
  12. mkLookupFun, findInList, assocElts,
  13. -- Duplicate handling
  14. hasNoDups, runs, removeDups, findDupsEq,
  15. equivClasses, equivClassesByUniq
  16. ) where
  17. import Outputable
  18. import Unique
  19. import UniqFM
  20. import Util
  21. import Data.List
  22. \end{code}
  23. %************************************************************************
  24. %* *
  25. Treating lists as sets
  26. Assumes the lists contain no duplicates, but are unordered
  27. %* *
  28. %************************************************************************
  29. \begin{code}
  30. insertList :: Eq a => a -> [a] -> [a]
  31. -- Assumes the arg list contains no dups; guarantees the result has no dups
  32. insertList x xs | isIn "insert" x xs = xs
  33. | otherwise = x : xs
  34. unionLists :: (Eq a) => [a] -> [a] -> [a]
  35. -- Assumes that the arguments contain no duplicates
  36. unionLists xs ys = [x | x <- xs, isn'tIn "unionLists" x ys] ++ ys
  37. minusList :: (Eq a) => [a] -> [a] -> [a]
  38. -- Everything in the first list that is not in the second list:
  39. minusList xs ys = [ x | x <- xs, isn'tIn "minusList" x ys]
  40. \end{code}
  41. %************************************************************************
  42. %* *
  43. \subsection[Utils-assoc]{Association lists}
  44. %* *
  45. %************************************************************************
  46. Inefficient finite maps based on association lists and equality.
  47. \begin{code}
  48. -- A finite mapping based on equality and association lists
  49. type Assoc a b = [(a,b)]
  50. emptyAssoc :: Assoc a b
  51. unitAssoc :: a -> b -> Assoc a b
  52. assocElts :: Assoc a b -> [(a,b)]
  53. assoc :: (Eq a) => String -> Assoc a b -> a -> b
  54. assocDefault :: (Eq a) => b -> Assoc a b -> a -> b
  55. assocUsing :: (a -> a -> Bool) -> String -> Assoc a b -> a -> b
  56. assocMaybe :: (Eq a) => Assoc a b -> a -> Maybe b
  57. assocDefaultUsing :: (a -> a -> Bool) -> b -> Assoc a b -> a -> b
  58. mapAssoc :: (b -> c) -> Assoc a b -> Assoc a c
  59. extendAssoc_C :: (Eq a) => (b -> b -> b) -> Assoc a b -> (a,b) -> Assoc a b
  60. plusAssoc_C :: (Eq a) => (b -> b -> b) -> Assoc a b -> Assoc a b -> Assoc a b
  61. -- combining fn takes (old->new->result)
  62. emptyAssoc = []
  63. unitAssoc a b = [(a,b)]
  64. assocElts xs = xs
  65. assocDefaultUsing _ deflt [] _ = deflt
  66. assocDefaultUsing eq deflt ((k,v) : rest) key
  67. | k `eq` key = v
  68. | otherwise = assocDefaultUsing eq deflt rest key
  69. assoc crash_msg list key = assocDefaultUsing (==) (panic ("Failed in assoc: " ++ crash_msg)) list key
  70. assocDefault deflt list key = assocDefaultUsing (==) deflt list key
  71. assocUsing eq crash_msg list key = assocDefaultUsing eq (panic ("Failed in assoc: " ++ crash_msg)) list key
  72. assocMaybe alist key
  73. = lookup alist
  74. where
  75. lookup [] = Nothing
  76. lookup ((tv,ty):rest) = if key == tv then Just ty else lookup rest
  77. mapAssoc f alist = [(key, f val) | (key,val) <- alist]
  78. plusAssoc_C _ [] new = new -- Shortcut for common case
  79. plusAssoc_C combine old new = foldl (extendAssoc_C combine) old new
  80. extendAssoc_C combine old_list (new_key, new_val)
  81. = go old_list
  82. where
  83. go [] = [(new_key, new_val)]
  84. go ((old_key, old_val) : old_list)
  85. | new_key == old_key = ((old_key, old_val `combine` new_val) : old_list)
  86. | otherwise = (old_key, old_val) : go old_list
  87. \end{code}
  88. @mkLookupFun eq alist@ is a function which looks up
  89. its argument in the association list @alist@, returning a Maybe type.
  90. @mkLookupFunDef@ is similar except that it is given a value to return
  91. on failure.
  92. \begin{code}
  93. mkLookupFun :: (key -> key -> Bool) -- Equality predicate
  94. -> [(key,val)] -- The assoc list
  95. -> key -- The key
  96. -> Maybe val -- The corresponding value
  97. mkLookupFun eq alist s
  98. = case [a | (s',a) <- alist, s' `eq` s] of
  99. [] -> Nothing
  100. (a:_) -> Just a
  101. findInList :: (a -> Bool) -> [a] -> Maybe a
  102. findInList _ [] = Nothing
  103. findInList p (x:xs) | p x = Just x
  104. | otherwise = findInList p xs
  105. \end{code}
  106. %************************************************************************
  107. %* *
  108. \subsection[Utils-dups]{Duplicate-handling}
  109. %* *
  110. %************************************************************************
  111. \begin{code}
  112. hasNoDups :: (Eq a) => [a] -> Bool
  113. hasNoDups xs = f [] xs
  114. where
  115. f _ [] = True
  116. f seen_so_far (x:xs) = if x `is_elem` seen_so_far
  117. then False
  118. else f (x:seen_so_far) xs
  119. is_elem = isIn "hasNoDups"
  120. \end{code}
  121. \begin{code}
  122. equivClasses :: (a -> a -> Ordering) -- Comparison
  123. -> [a]
  124. -> [[a]]
  125. equivClasses _ [] = []
  126. equivClasses _ stuff@[_] = [stuff]
  127. equivClasses cmp items = runs eq (sortLe le items)
  128. where
  129. eq a b = case cmp a b of { EQ -> True; _ -> False }
  130. le a b = case cmp a b of { LT -> True; EQ -> True; GT -> False }
  131. \end{code}
  132. The first cases in @equivClasses@ above are just to cut to the point
  133. more quickly...
  134. @runs@ groups a list into a list of lists, each sublist being a run of
  135. identical elements of the input list. It is passed a predicate @p@ which
  136. tells when two elements are equal.
  137. \begin{code}
  138. runs :: (a -> a -> Bool) -- Equality
  139. -> [a]
  140. -> [[a]]
  141. runs _ [] = []
  142. runs p (x:xs) = case (span (p x) xs) of
  143. (first, rest) -> (x:first) : (runs p rest)
  144. \end{code}
  145. \begin{code}
  146. removeDups :: (a -> a -> Ordering) -- Comparison function
  147. -> [a]
  148. -> ([a], -- List with no duplicates
  149. [[a]]) -- List of duplicate groups. One representative from
  150. -- each group appears in the first result
  151. removeDups _ [] = ([], [])
  152. removeDups _ [x] = ([x],[])
  153. removeDups cmp xs
  154. = case (mapAccumR collect_dups [] (equivClasses cmp xs)) of { (dups, xs') ->
  155. (xs', dups) }
  156. where
  157. collect_dups _ [] = panic "ListSetOps: removeDups"
  158. collect_dups dups_so_far [x] = (dups_so_far, x)
  159. collect_dups dups_so_far dups@(x:_) = (dups:dups_so_far, x)
  160. findDupsEq :: (a->a->Bool) -> [a] -> [[a]]
  161. findDupsEq _ [] = []
  162. findDupsEq eq (x:xs) | null eq_xs = findDupsEq eq xs
  163. | otherwise = (x:eq_xs) : findDupsEq eq neq_xs
  164. where (eq_xs, neq_xs) = partition (eq x) xs
  165. \end{code}
  166. \begin{code}
  167. equivClassesByUniq :: (a -> Unique) -> [a] -> [[a]]
  168. -- NB: it's *very* important that if we have the input list [a,b,c],
  169. -- where a,b,c all have the same unique, then we get back the list
  170. -- [a,b,c]
  171. -- not
  172. -- [c,b,a]
  173. -- Hence the use of foldr, plus the reversed-args tack_on below
  174. equivClassesByUniq get_uniq xs
  175. = eltsUFM (foldr add emptyUFM xs)
  176. where
  177. add a ufm = addToUFM_C tack_on ufm (get_uniq a) [a]
  178. tack_on old new = new++old
  179. \end{code}