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