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