[project @ 1996-03-19 08:58:34 by partain]
[ghc-hetmet.git] / ghc / compiler / utils / Maybes.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
3 %
4 \section[Maybes]{The `Maybe' types and associated utility functions}
5
6 \begin{code}
7 #if defined(COMPILING_GHC)
8 #include "HsVersions.h"
9 #endif
10
11 module Maybes (
12 --      Maybe(..), -- no, it's in 1.3
13         MaybeErr(..),
14
15         allMaybes,      -- GHCI only
16         catMaybes,
17         firstJust,
18         expectJust,
19         maybeToBool,
20
21         assocMaybe,
22         mkLookupFun, mkLookupFunDef,
23
24         failMaB,
25         failMaybe,
26         seqMaybe,
27         mapMaybe,       -- GHCI only
28         returnMaB,
29         returnMaybe,    -- GHCI only
30         thenMaB,
31         thenMaybe       -- GHCI only
32
33 #if ! defined(COMPILING_GHC)
34         , findJust
35         , foldlMaybeErrs
36         , listMaybeErrs
37 #endif
38     ) where
39
40 #if defined(COMPILING_GHC)
41
42 CHK_Ubiq() -- debugging consistency check
43
44 #if USE_ATTACK_PRAGMAS
45 import Util
46 #endif
47 #endif
48 \end{code}
49
50
51 %************************************************************************
52 %*                                                                      *
53 \subsection[Maybe type]{The @Maybe@ type}
54 %*                                                                      *
55 %************************************************************************
56
57 \begin{code}
58 #if __HASKELL1__ < 3
59 data Maybe a
60   = Nothing
61   | Just a
62 #endif
63 \end{code}
64
65 \begin{code}
66 maybeToBool :: Maybe a -> Bool
67 maybeToBool Nothing  = False
68 maybeToBool (Just x) = True
69 \end{code}
70
71 @catMaybes@ takes a list of @Maybe@s and returns a list of
72 the contents of all the @Just@s in it.  @allMaybes@ collects
73 a list of @Justs@ into a single @Just@, returning @Nothing@ if there
74 are any @Nothings@.
75
76 \begin{code}
77 catMaybes :: [Maybe a] -> [a]
78 catMaybes []                = []
79 catMaybes (Nothing : xs)   = catMaybes xs
80 catMaybes (Just x : xs)    = (x : catMaybes xs)
81
82 allMaybes :: [Maybe a] -> Maybe [a]
83 allMaybes [] = Just []
84 allMaybes (Nothing : ms) = Nothing
85 allMaybes (Just x  : ms) = case (allMaybes ms) of
86                              Nothing -> Nothing
87                              Just xs -> Just (x:xs)
88 \end{code}
89
90 @firstJust@ takes a list of @Maybes@ and returns the
91 first @Just@ if there is one, or @Nothing@ otherwise.
92
93 \begin{code}
94 firstJust :: [Maybe a] -> Maybe a
95 firstJust [] = Nothing
96 firstJust (Just x  : ms) = Just x
97 firstJust (Nothing : ms) = firstJust ms
98 \end{code}
99
100 \begin{code}
101 findJust :: (a -> Maybe b) -> [a] -> Maybe b
102 findJust f []     = Nothing
103 findJust f (a:as) = case f a of
104                       Nothing -> findJust f as
105                       b  -> b
106 \end{code}
107
108 \begin{code}
109 expectJust :: String -> Maybe a -> a
110 {-# INLINE expectJust #-}
111 expectJust err (Just x) = x
112 expectJust err Nothing  = error ("expectJust " ++ err)
113 \end{code}
114
115 The Maybe monad
116 ~~~~~~~~~~~~~~~
117 \begin{code}
118 #if __HASKELL1__ < 3
119 thenMaybe :: Maybe a -> (a -> Maybe b) -> Maybe b
120 m `thenMaybe` k = case m of
121                   Nothing -> Nothing
122                   Just a  -> k a
123 #endif
124
125 seqMaybe :: Maybe a -> Maybe a -> Maybe a
126 seqMaybe (Just x) _  = Just x
127 seqMaybe Nothing  my = my
128
129 returnMaybe :: a -> Maybe a
130 returnMaybe = Just
131
132 failMaybe :: Maybe a
133 failMaybe = Nothing
134
135 mapMaybe :: (a -> Maybe b) -> [a] -> Maybe [b]
136 mapMaybe f []     = returnMaybe []
137 mapMaybe f (x:xs) = f x                 `thenMaybe` \ x' ->
138                     mapMaybe f xs       `thenMaybe` \ xs' ->
139                     returnMaybe (x':xs')
140 \end{code}
141
142 Lookup functions
143 ~~~~~~~~~~~~~~~~
144
145 @assocMaybe@ looks up in an assocation list, returning
146 @Nothing@ if it fails.
147
148 \begin{code}
149 assocMaybe :: (Eq a) => [(a,b)] -> a -> Maybe b
150
151 assocMaybe alist key
152   = lookup alist
153   where
154     lookup []             = Nothing
155     lookup ((tv,ty):rest) = if key == tv then Just ty else lookup rest
156
157 #if defined(COMPILING_GHC)
158 {-? SPECIALIZE assocMaybe
159         :: [(String,        b)] -> String        -> Maybe b,
160            [(Id,            b)] -> Id            -> Maybe b,
161            [(Class,         b)] -> Class         -> Maybe b,
162            [(Int,           b)] -> Int           -> Maybe b,
163            [(Name,          b)] -> Name          -> Maybe b,
164            [(TyVar,         b)] -> TyVar         -> Maybe b,
165            [(TyVarTemplate, b)] -> TyVarTemplate -> Maybe b
166   #-}
167 #endif
168 \end{code}
169
170 @mkLookupFun eq alist@ is a function which looks up
171 its argument in the association list @alist@, returning a Maybe type.
172 @mkLookupFunDef@ is similar except that it is given a value to return
173 on failure.
174
175 \begin{code}
176 mkLookupFun :: (key -> key -> Bool)     -- Equality predicate
177             -> [(key,val)]              -- The assoc list
178             -> key                      -- The key
179             -> Maybe val                -- The corresponding value
180
181 mkLookupFun eq alist s
182   = case [a | (s',a) <- alist, s' `eq` s] of
183       []    -> Nothing
184       (a:_) -> Just a
185
186 mkLookupFunDef :: (key -> key -> Bool)  -- Equality predicate
187                -> [(key,val)]           -- The assoc list
188                -> val                   -- Value to return on failure
189                -> key                   -- The key
190                -> val                   -- The corresponding value
191
192 mkLookupFunDef eq alist deflt s
193   = case [a | (s',a) <- alist, s' `eq` s] of
194       []    -> deflt
195       (a:_) -> a
196 \end{code}
197
198 %************************************************************************
199 %*                                                                      *
200 \subsection[MaybeErr type]{The @MaybeErr@ type}
201 %*                                                                      *
202 %************************************************************************
203
204 \begin{code}
205 data MaybeErr val err = Succeeded val | Failed err
206 \end{code}
207
208 \begin{code}
209 thenMaB :: MaybeErr val1 err -> (val1 -> MaybeErr val2 err) -> MaybeErr val2 err
210 thenMaB m k
211   = case m of
212       Succeeded v -> k v
213       Failed e    -> Failed e
214
215 returnMaB :: val -> MaybeErr val err
216 returnMaB v = Succeeded v
217
218 failMaB :: err -> MaybeErr val err
219 failMaB e = Failed e
220 \end{code}
221
222
223 @listMaybeErrs@ takes a list of @MaybeErrs@ and, if they all succeed, returns
224 a @Succeeded@ of a list of their values.  If any fail, it returns a
225 @Failed@ of the list of all the errors in the list.
226
227 \begin{code}
228 listMaybeErrs :: [MaybeErr val err] -> MaybeErr [val] [err]
229 listMaybeErrs
230   = foldr combine (Succeeded [])
231   where
232     combine (Succeeded v) (Succeeded vs) = Succeeded (v:vs)
233     combine (Failed err)  (Succeeded _)  = Failed [err]
234     combine (Succeeded v) (Failed errs)  = Failed errs
235     combine (Failed err)  (Failed errs)  = Failed (err:errs)
236 \end{code}
237
238 @foldlMaybeErrs@ works along a list, carrying an accumulator; it
239 applies the given function to the accumulator and the next list item,
240 accumulating any errors that occur.
241
242 \begin{code}
243 foldlMaybeErrs :: (acc -> input -> MaybeErr acc err)
244                -> acc
245                -> [input]
246                -> MaybeErr acc [err]
247
248 foldlMaybeErrs k accum ins = do_it [] accum ins
249   where
250     do_it []   acc []     = Succeeded acc
251     do_it errs acc []     = Failed errs
252     do_it errs acc (v:vs) = case (k acc v) of
253                               Succeeded acc' -> do_it errs       acc' vs
254                               Failed err     -> do_it (err:errs) acc  vs
255 \end{code}