1 Some General Utilities, including sorts, etc.
2 This is realy just an extended prelude.
3 All the code below is understood to be in the public domain.
5 Changed to use \begin\end code, to help
6 as a test example for STG Hugs.
13 assocMaybe, assocMaybeErr,
43 #ifndef __GLASGOW_HASKELL__
45 import {-fool mkdependHS-}
50 -- -------------------------------------------------------------------------
52 -- Here are two defs that everyone seems to define ...
53 -- HBC has it in one of its builtin modules
55 #if defined(__GLASGOW_HASKELL__) || defined(__GOFER__)
57 --in 1.3: data Maybe a = Nothing | Just a deriving (Eq,Ord,Text)
62 type Assoc a b = (a,b) -- 1.3
65 mapMaybe :: (a -> Maybe b) -> [a] -> [b]
67 mapMaybe f (a:r) = case f a of
68 Nothing -> mapMaybe f r
69 Just b -> b : mapMaybe f r
71 -- This version returns nothing, if *any* one fails.
73 mapMaybeFail f (x:xs) = case f x of
74 Just x' -> case mapMaybeFail f xs of
75 Just xs' -> Just (x':xs')
78 mapMaybeFail f [] = Just []
80 maybeToBool :: Maybe a -> Bool
81 maybeToBool (Just _) = True
84 maybeToObj :: Maybe a -> a
85 maybeToObj (Just a) = a
86 maybeToObj _ = error "Trying to extract object from a Nothing"
88 maybeMap :: (a -> b) -> Maybe a -> Maybe b
89 maybeMap f (Just a) = Just (f a)
90 maybeMap f Nothing = Nothing
93 joinMaybe :: (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a
94 joinMaybe _ Nothing Nothing = Nothing
95 joinMaybe _ (Just g) Nothing = Just g
96 joinMaybe _ Nothing (Just g) = Just g
97 joinMaybe f (Just g) (Just h) = Just (f g h)
99 data MaybeErr a err = Succeeded a | Failed err deriving (Eq,Show{-was:Text-})
101 -- @mkClosure@ makes a closure, when given a comparison and iteration loop.
102 -- Be careful, because if the functional always makes the object different,
103 -- This will never terminate.
105 mkClosure :: (a -> a -> Bool) -> (a -> a) -> a -> a
106 mkClosure eq f = match . iterate f
108 match (a:b:c) | a `eq` b = a
109 match (_:c) = match c
112 -- It combines the element of the list argument in balanced mannerism.
114 foldb :: (a -> a -> a) -> [a] -> a
115 foldb f [] = error "can't reduce an empty list using foldb"
117 foldb f l = foldb f (foldb' l)
119 foldb' (x:y:x':y':xs) = f (f x y) (f x' y') : foldb' xs
120 foldb' (x:y:xs) = f x y : foldb' xs
123 -- Merge two ordered lists into one ordered list.
125 mergeWith :: (a -> a -> Bool) -> [a] -> [a] -> [a]
126 mergeWith _ [] ys = ys
127 mergeWith _ xs [] = xs
128 mergeWith le (x:xs) (y:ys)
129 | x `le` y = x : mergeWith le xs (y:ys)
130 | otherwise = y : mergeWith le (x:xs) ys
132 insertWith :: (a -> a -> Bool) -> a -> [a] -> [a]
133 insertWith _ x [] = [x]
134 insertWith le x (y:ys)
136 | otherwise = y:insertWith le x ys
138 -- Sorting is something almost every program needs, and this is the
139 -- quickest sorting function I know of.
141 sortWith :: (a -> a -> Bool) -> [a] -> [a]
143 sortWith le lst = foldb (mergeWith le) (splitList lst)
145 splitList (a1:a2:a3:a4:a5:xs) =
149 (insertWith le a4 [a5]))) : splitList xs
151 splitList (r:rs) = [foldr (insertWith le) [r] rs]
153 sort :: (Ord a) => [a] -> [a]
158 cjustify, ljustify, rjustify :: Int -> String -> String
159 cjustify n s = space halfm ++ s ++ space (m - halfm)
160 where m = n - length s
162 ljustify n s = s ++ space (max 0 (n - length s))
163 rjustify n s = space (max 0 (n - length s)) ++ s
165 space :: Int -> String
168 copy :: Int -> a -> [a] -- make list of n copies of x
169 copy n x = take n xs where xs = x:xs
171 combinePairs :: (Ord a) => [(a,b)] -> [(a,[b])]
173 combine [ (a,[b]) | (a,b) <- sortWith (\ (a,_) (b,_) -> a <= b) xs]
176 combine ((a,b):(c,d):r) | a == c = combine ((a,b++d) : r)
177 combine (a:r) = a : combine r
179 assocMaybe :: (Eq a) => [(a,b)] -> a -> Maybe b
180 assocMaybe env k = case [ val | (key,val) <- env, k == key] of
184 assocMaybeErr :: (Eq a) => [(a,b)] -> a -> MaybeErr b String
185 assocMaybeErr env k = case [ val | (key,val) <- env, k == key] of
186 [] -> Failed "assoc: "
187 (val:vs) -> Succeeded val
190 deSucc (Succeeded e) = e
192 mapAccumL :: (a -> b -> (c,a)) -> a -> [b] -> ([c],a)
193 mapAccumL f s [] = ([],s)
194 mapAccumL f s (b:bs) = (c:cs,s'')
197 (cs,s'') = mapAccumL f s' bs
201 -- Now some utilties involving arrays.
202 -- Here is a version of @elem@ that uses partual application
203 -- to optimise lookup.
205 arrElem :: (Ix a) => [a] -> a -> Bool
206 arrElem obj = \x -> inRange size x && arr ! x
208 size = (maximum obj,minimum obj)
209 arr = listArray size [ i `elem` obj | i <- range size ]
211 -- Here is the functional version of a multi-way conditional,
212 -- again using arrays, of course. Remember @b@ can be a function !
213 -- Note again the use of partiual application.
216 => (a,a) -- the bounds
217 -> [(Assoc [a] b)] -- the simple lookups
218 -> [(Assoc (a -> Bool) b)] -- the functional lookups
220 -> a -> b -- the (functional) result
222 arrCond bds pairs fnPairs def = (!) arr'
224 arr' = array bds [ t =: head
225 ([ r | (p, r) <- pairs, elem t p ] ++
226 [ r | (f, r) <- fnPairs, f t ] ++
230 memoise :: (Ix a) => (a,a) -> (a -> b) -> a -> b
231 memoise bds f = (!) arr
232 where arr = array bds [ t =: f t | t <- range bds ]
234 -- Quite neat this. Formats text to fit in a column.
236 formatText :: Int -> [String] -> [String]
237 formatText n = map unwords . cutAt n []
239 cutAt :: Int -> [String] -> [String] -> [[String]]
240 cutAt m wds [] = [reverse wds]
241 cutAt m wds (wd:rest) = if len <= m || null wds
242 then cutAt (m-(len+1)) (wd:wds) rest
243 else reverse wds : cutAt n [] (wd:rest)
244 where len = length wd