summaryrefslogtreecommitdiff
path: root/compiler/utils/Maybes.hs
blob: 56b6dab5d92e373510b65cd093984cd003abe4ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
{-
(c) The University of Glasgow 2006
(c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-}

{-# LANGUAGE CPP #-}
module Maybes (
        module Data.Maybe,

        MaybeErr(..), -- Instance of Monad
        failME, isSuccess,

        orElse,
        firstJust, firstJusts,
        whenIsJust,
        expectJust,

        MaybeT(..), liftMaybeT
    ) where

import Control.Applicative
import Control.Monad
import Data.Maybe

infixr 4 `orElse`

{-
************************************************************************
*                                                                      *
\subsection[Maybe type]{The @Maybe@ type}
*                                                                      *
************************************************************************
-}

firstJust :: Maybe a -> Maybe a -> Maybe a
firstJust a b = firstJusts [a, b]

-- | Takes a list of @Maybes@ and returns the first @Just@ if there is one, or
-- @Nothing@ otherwise.
firstJusts :: [Maybe a] -> Maybe a
firstJusts = msum

expectJust :: String -> Maybe a -> a
{-# INLINE expectJust #-}
expectJust _   (Just x) = x
expectJust err Nothing  = error ("expectJust " ++ err)

whenIsJust :: Monad m => Maybe a -> (a -> m ()) -> m ()
whenIsJust (Just x) f = f x
whenIsJust Nothing  _ = return ()

-- | Flipped version of @fromMaybe@, useful for chaining.
orElse :: Maybe a -> a -> a
orElse = flip fromMaybe

{-
************************************************************************
*                                                                      *
\subsection[MaybeT type]{The @MaybeT@ monad transformer}
*                                                                      *
************************************************************************
-}

newtype MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)}

instance Functor m => Functor (MaybeT m) where
  fmap f x = MaybeT $ fmap (fmap f) $ runMaybeT x

#if __GLASGOW_HASKELL__ < 710
-- Pre-AMP change
instance (Monad m, Applicative m) => Applicative (MaybeT m) where
#else
instance (Monad m) => Applicative (MaybeT m) where
#endif
  pure = MaybeT . pure . Just
  (<*>) = ap

#if __GLASGOW_HASKELL__ < 710
-- Pre-AMP change
instance (Monad m, Applicative m) => Monad (MaybeT m) where
#else
instance (Monad m) => Monad (MaybeT m) where
#endif
  return = pure
  x >>= f = MaybeT $ runMaybeT x >>= maybe (pure Nothing) (runMaybeT . f)
  fail _ = MaybeT $ pure Nothing

#if __GLASGOW_HASKELL__ < 710
-- Pre-AMP change
instance (Monad m, Applicative m) => Alternative (MaybeT m) where
#else
instance (Monad m) => Alternative (MaybeT m) where
#endif
  empty = mzero
  (<|>) = mplus

#if __GLASGOW_HASKELL__ < 710
-- Pre-AMP change
instance (Monad m, Applicative m) => MonadPlus (MaybeT m) where
#else
instance Monad m => MonadPlus (MaybeT m) where
#endif
  mzero       = MaybeT $ pure Nothing
  p `mplus` q = MaybeT $ do ma <- runMaybeT p
                            case ma of
                              Just a  -> pure (Just a)
                              Nothing -> runMaybeT q

liftMaybeT :: Monad m => m a -> MaybeT m a
liftMaybeT act = MaybeT $ Just `liftM` act

{-
************************************************************************
*                                                                      *
\subsection[MaybeErr type]{The @MaybeErr@ type}
*                                                                      *
************************************************************************
-}

data MaybeErr err val = Succeeded val | Failed err

instance Functor (MaybeErr err) where
  fmap = liftM

instance Applicative (MaybeErr err) where
  pure  = Succeeded
  (<*>) = ap

instance Monad (MaybeErr err) where
  return = pure
  Succeeded v >>= k = k v
  Failed e    >>= _ = Failed e

isSuccess :: MaybeErr err val -> Bool
isSuccess (Succeeded {}) = True
isSuccess (Failed {})    = False

failME :: err -> MaybeErr err val
failME e = Failed e