1 -----------------------------------------------------------------------------
2 -- $Id: GenUtils.lhs,v 1.1 1999/11/12 11:54:17 simonmar Exp $
4 -- Some General Utilities, including sorts, etc.
5 -- This is realy just an extended prelude.
6 -- All the code below is understood to be in the public domain.
7 -----------------------------------------------------------------------------
15 > returnMaybe,handleMaybe, findJust,
29 > --trace, -- re-export it
34 #if __HASKELL1__ < 3 || ( defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 200 )
36 > ,Cmp(..), compare, lookup, isJust
42 #if __HASKELL1__ >= 3 && ( !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ >= 200 )
44 > import Ix ( Ix(..) )
45 > import Array ( listArray, array, (!) )
48 #define ASSOC(a,b) (a , b)
50 #define ASSOC(a,b) (a := b)
53 %------------------------------------------------------------------------------
55 Here are two defs that everyone seems to define ...
56 HBC has it in one of its builtin modules
60 primitive primPrint "primPrint" :: Int -> a -> ShowS
66 primitive primGenericEq "primGenericEq",
67 primGenericNe "primGenericNe",
68 primGenericLe "primGenericLe",
69 primGenericLt "primGenericLt",
70 primGenericGe "primGenericGe",
71 primGenericGt "primGenericGt" :: a -> a -> Bool
73 instance Text (Maybe a) where { showsPrec = primPrint }
74 instance Eq (Maybe a) where
78 instance (Ord a) => Ord (Maybe a)
82 (Just a) <= (Just b) = a <= b
86 > maybeMap :: (a -> b) -> Maybe a -> Maybe b
87 > maybeMap f (Just a) = Just (f a)
88 > maybeMap f Nothing = Nothing
90 > joinMaybe :: (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a
91 > joinMaybe _ Nothing Nothing = Nothing
92 > joinMaybe _ (Just g) Nothing = Just g
93 > joinMaybe _ Nothing (Just g) = Just g
94 > joinMaybe f (Just g) (Just h) = Just (f g h)
96 > data MaybeErr a err = Succeeded a | Failed err deriving (Eq,Text)
98 @mkClosure@ makes a closure, when given a comparison and iteration loop.
99 Be careful, because if the functional always makes the object different,
100 This will never terminate.
102 > mkClosure :: (a -> a -> Bool) -> (a -> a) -> a -> a
103 > mkClosure eq f = match . iterate f
105 > match (a:b:c) | a `eq` b = a
106 > match (_:c) = match c
108 > foldb :: (a -> a -> a) -> [a] -> a
109 > foldb f [] = error "can't reduce an empty list using foldb"
111 > foldb f l = foldb f (foldb' l)
113 > foldb' (x:y:x':y':xs) = f (f x y) (f x' y') : foldb' xs
114 > foldb' (x:y:xs) = f x y : foldb' xs
117 Merge two ordered lists into one ordered list.
119 > mergeWith :: (a -> a -> Bool) -> [a] -> [a] -> [a]
120 > mergeWith _ [] ys = ys
121 > mergeWith _ xs [] = xs
122 > mergeWith le (x:xs) (y:ys)
123 > | x `le` y = x : mergeWith le xs (y:ys)
124 > | otherwise = y : mergeWith le (x:xs) ys
126 > insertWith :: (a -> a -> Bool) -> a -> [a] -> [a]
127 > insertWith _ x [] = [x]
128 > insertWith le x (y:ys)
129 > | x `le` y = x:y:ys
130 > | otherwise = y:insertWith le x ys
132 Sorting is something almost every program needs, and this is the
133 quickest sorting function I know of.
135 > sortWith :: (a -> a -> Bool) -> [a] -> [a]
136 > sortWith le [] = []
137 > sortWith le lst = foldb (mergeWith le) (splitList lst)
139 > splitList (a1:a2:a3:a4:a5:xs) =
143 > (insertWith le a4 [a5]))) : splitList xs
145 > splitList (r:rs) = [foldr (insertWith le) [r] rs]
147 > sort :: (Ord a) => [a] -> [a]
148 > sort = sortWith (<=)
150 > returnMaybe :: a -> Maybe a
153 > handleMaybe :: Maybe a -> Maybe a -> Maybe a
154 > handleMaybe m k = case m of
158 > findJust :: (a -> Maybe b) -> [a] -> Maybe b
159 > findJust f = foldr handleMaybe Nothing . map f
168 > cjustify, ljustify, rjustify :: Int -> String -> String
169 > cjustify n s = space halfm ++ s ++ space (m - halfm)
170 > where m = n - length s
172 > ljustify n s = s ++ space (n - length s)
173 > rjustify n s = let s' = take n s in space (n - length s') ++ s'
175 > space :: Int -> String
176 > space n | n < 0 = ""
177 > | otherwise = copy n ' '
179 > copy :: Int -> a -> [a] -- make list of n copies of x
180 > copy n x = take n xs where xs = x:xs
182 > partition' :: (Eq b) => (a -> b) -> [a] -> [[a]]
183 > partition' f [] = []
184 > partition' f [x] = [[x]]
185 > partition' f (x:x':xs) | f x == f x'
186 > = tack x (partition' f (x':xs))
188 > = [x] : partition' f (x':xs)
190 > tack x xss = (x : head xss) : tail xss
192 > combinePairs :: (Ord a) => [(a,b)] -> [(a,[b])]
194 > combine [ (a,[b]) | (a,b) <- sortWith (\ (a,_) (b,_) -> a <= b) xs]
197 > combine ((a,b):(c,d):r) | a == c = combine ((a,b++d) : r)
198 > combine (a:r) = a : combine r
201 #if __HASKELL1__ < 3 || ( defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 200 )
203 > lookup :: (Eq a) => a -> [(a,b)] -> Maybe b
204 > lookup k env = case [ val | (key,val) <- env, k == key] of
206 > (val:vs) -> Just val
209 > data Cmp = LT | EQ | GT
211 > compare a b | a < b = LT
215 > isJust :: Maybe a -> Bool
216 > isJust (Just _) = True
221 > assocMaybeErr :: (Eq a) => [(a,b)] -> a -> MaybeErr b String
222 > assocMaybeErr env k = case [ val | (key,val) <- env, k == key] of
223 > [] -> Failed "assoc: "
224 > (val:vs) -> Succeeded val
227 Now some utilties involving arrays.
228 Here is a version of @elem@ that uses partual application
231 > arrElem :: (Ix a) => [a] -> a -> Bool
232 > arrElem obj = \x -> inRange size x && arr ! x
235 > size = (head obj',last obj')
236 > arr = listArray size [ i `elem` obj | i <- range size ]
239 You can use this function to simulate memoisation. For example:
241 > fib = memoise (0,100) fib'
245 > fib' n = fib (n-1) + fib (n-2)
247 will give a very efficent variation of the fib function.
250 > memoise :: (Ix a) => (a,a) -> (a -> b) -> a -> b
251 > memoise bds f = (!) arr
252 > where arr = array bds [ ASSOC(t, f t) | t <- range bds ]
254 > mapAccumR :: (acc -> x -> (acc, y)) -- Function of elt of input list
255 > -- and accumulator, returning new
256 > -- accumulator and elt of result list
257 > -> acc -- Initial accumulator
258 > -> [x] -- Input list
259 > -> (acc, [y]) -- Final accumulator and result list
261 > mapAccumR f b [] = (b, [])
262 > mapAccumR f b (x:xs) = (b'', x':xs') where
264 > (b', xs') = mapAccumR f b xs
266 > mapAccumL :: (acc -> x -> (acc, y)) -- Function of elt of input list
267 > -- and accumulator, returning new
268 > -- accumulator and elt of result list
269 > -> acc -- Initial accumulator
270 > -> [x] -- Input list
271 > -> (acc, [y]) -- Final accumulator and result list
273 > mapAccumL f b [] = (b, [])
274 > mapAccumL f b (x:xs) = (b'', x':xs') where
276 > (b'', xs') = mapAccumL f b' xs
278 Here is the bi-directional version ...
280 > mapAccumB :: (accl -> accr -> x -> (accl, accr,y))
281 > -- Function of elt of input list
282 > -- and accumulator, returning new
283 > -- accumulator and elt of result list
284 > -> accl -- Initial accumulator from left
285 > -> accr -- Initial accumulator from right
286 > -> [x] -- Input list
287 > -> (accl, accr, [y]) -- Final accumulator and result list
289 > mapAccumB f a b [] = (a,b,[])
290 > mapAccumB f a b (x:xs) = (a'',b'',y:ys)
292 > (a',b'',y) = f a b' x
293 > (a'',b',ys) = mapAccumB f a' b xs
296 > assert False x = error "assert Failed"