mirror of
https://github.com/idris-lang/Idris2.git
synced 2024-12-22 03:01:31 +03:00
394613432f
Co-authored-by: Zoe Stafford <36511192+Z-snails@users.noreply.github.com>
173 lines
5.0 KiB
Idris
173 lines
5.0 KiB
Idris
module Control.Monad.Maybe
|
|
|
|
-------------------------------------------------
|
|
-- The monad transformer `MaybeT m a` equips a monad with the ability to
|
|
-- return no value at all.
|
|
|
|
-- Sequenced actions of `MaybeT m a` produce a value `a` only if all of the
|
|
-- actions in the sequence returned a value.
|
|
|
|
-- This is isomorphic to `EitherT ()` and therefore less powerful than `EitherT e a`
|
|
-- ability to not return a result.
|
|
-------------------------------------------------
|
|
|
|
import Control.Monad.Trans
|
|
import Data.Maybe
|
|
|
|
%default total
|
|
|
|
||| A monad transformer extending an inner monad with the ability to not return
|
|
||| a result.
|
|
|||
|
|
||| Sequenced actions produce a result only if both actions return a result.
|
|
|||
|
|
||| `MaybeT m a` is equivalent to `EitherT () m a`, that is, an computation
|
|
||| that can only throw a single, information-less exception.
|
|
public export
|
|
data MaybeT : (m : Type -> Type) -> (a : Type) -> Type where
|
|
MkMaybeT : m (Maybe a) -> MaybeT m a
|
|
|
|
||| Unwrap a `MaybeT` computation.
|
|
public export
|
|
%inline
|
|
runMaybeT : MaybeT m a -> m (Maybe a)
|
|
runMaybeT (MkMaybeT x) = x
|
|
|
|
||| Check if a monadic computation returns a result. This returns `False` if
|
|
||| the computation returns a result, and `True` otherwise.
|
|
|||
|
|
||| This is a version of `isNothing` lifted to work with `MaybeT`.
|
|
public export
|
|
%inline
|
|
isNothingT : Functor m => MaybeT m a -> m Bool
|
|
isNothingT = map isNothing . runMaybeT
|
|
|
|
||| Check if a monadic computation returns a result. This returns `True` if
|
|
||| the computation returns a result, and `False` otherwise.
|
|
|||
|
|
||| This is a version of `isJust` lifted to work with `MaybeT`.
|
|
public export
|
|
%inline
|
|
isJustT : Functor m => MaybeT m a -> m Bool
|
|
isJustT = map isJust . runMaybeT
|
|
|
|
||| Run a `MaybeT` computation, handling the case of a result or no result
|
|
||| seperately.
|
|
|||
|
|
||| This is a version of `maybe` lifted to work with `MaybeT`.
|
|
public export
|
|
%inline
|
|
maybeT : Monad m => m b -> (a -> m b) -> MaybeT m a -> m b
|
|
maybeT v g x = runMaybeT x >>= maybe v g
|
|
|
|
||| Run a `MaybeT` computation providing a default value.
|
|
|||
|
|
||| This is a version of `fromMaybe` lifted to work with `MaybeT`.
|
|
public export
|
|
%inline
|
|
fromMaybeT : Monad m => m a -> MaybeT m a -> m a
|
|
fromMaybeT v x = runMaybeT x >>= maybe v pure
|
|
|
|
||| Return a value if a condition is met, or else no value.
|
|
|||
|
|
||| This is a version of `toMaybe` lifted to work with `MaybeT`.
|
|
public export
|
|
%inline
|
|
toMaybeT : Functor m => Bool -> m a -> MaybeT m a
|
|
toMaybeT b m = MkMaybeT $ map (\a => toMaybe b a) m
|
|
|
|
||| Map over the underlying computation.
|
|
public export
|
|
%inline
|
|
mapMaybeT : (m (Maybe a) -> n (Maybe a')) -> MaybeT m a -> MaybeT n a'
|
|
mapMaybeT f = MkMaybeT . f . runMaybeT
|
|
|
|
||| A version of `Just` lifted to work with `MaybeT`.
|
|
|||
|
|
||| This is equivalent to `pure`.
|
|
public export
|
|
%inline
|
|
just : Applicative m => a -> MaybeT m a
|
|
just = MkMaybeT . pure . Just
|
|
|
|
||| A version of `Nothing` lifted to work with `MaybeT`.
|
|
|||
|
|
||| This is equivalent to `throwE ()`.
|
|
public export
|
|
%inline
|
|
nothing : Applicative m => MaybeT m a
|
|
nothing = MkMaybeT $ pure Nothing
|
|
|
|
-------------------------------------------------
|
|
-- Interface Implementations
|
|
-------------------------------------------------
|
|
|
|
public export
|
|
Eq (m (Maybe a)) => Eq (MaybeT m a) where
|
|
(==) = (==) `on` runMaybeT
|
|
|
|
public export
|
|
Ord (m (Maybe a)) => Ord (MaybeT m a) where
|
|
compare = compare `on` runMaybeT
|
|
|
|
public export
|
|
Show (m (Maybe a)) => Show (MaybeT m a) where
|
|
showPrec d (MkMaybeT x) = showCon d "MkMaybeT" $ showArg x
|
|
|
|
||| Corresponds to the Semigroup instance of Maybe
|
|
|||
|
|
||| Note: This could also be implemented with only an Applicative
|
|
||| prerequisite: `MkMaybeT x <+> MkMaybeT y = MkMaybeT $ [| x <+> y |]`
|
|
||| However, the monadic version is more efficient for long-running effects,
|
|
||| only evaluating the second argument if the first returns `Nothing`.
|
|
public export
|
|
Monad m => Semigroup (MaybeT m a) where
|
|
MkMaybeT x <+> MkMaybeT y = MkMaybeT $ do
|
|
r@(Just _) <- x | Nothing => y
|
|
pure r
|
|
|
|
public export
|
|
Monad m => Monoid (MaybeT m a) where
|
|
neutral = nothing
|
|
|
|
public export
|
|
Functor m => Functor (MaybeT m) where
|
|
map f m = MkMaybeT $ map f <$> runMaybeT m
|
|
|
|
public export
|
|
Foldable m => Foldable (MaybeT m) where
|
|
foldr f acc (MkMaybeT e)
|
|
= foldr (\x,xs => maybe xs (`f` xs) x) acc e
|
|
|
|
null (MkMaybeT e) = null e
|
|
|
|
public export
|
|
Traversable m => Traversable (MaybeT m) where
|
|
traverse f (MkMaybeT x)
|
|
= MkMaybeT <$> traverse (maybe (pure Nothing) (map Just . f)) x
|
|
|
|
public export
|
|
Applicative m => Applicative (MaybeT m) where
|
|
pure = just
|
|
MkMaybeT f <*> MkMaybeT x = MkMaybeT [| f <*> x |]
|
|
|
|
public export
|
|
Monad m => Monad (MaybeT m) where
|
|
MkMaybeT x >>= k = MkMaybeT $ x >>= maybe (pure Nothing) (runMaybeT . k)
|
|
|
|
||| See note about Monad prerequisite on Semigroup instance.
|
|
public export
|
|
Monad m => Alternative (MaybeT m) where
|
|
empty = nothing
|
|
MkMaybeT x <|> my = MkMaybeT $ x >>= \case
|
|
r@(Just _) => pure r
|
|
Nothing => runMaybeT my
|
|
|
|
public export
|
|
MonadTrans MaybeT where
|
|
lift = MkMaybeT . map Just
|
|
|
|
public export
|
|
HasIO m => HasIO (MaybeT m) where
|
|
liftIO act = MkMaybeT $ liftIO (io_bind act (pure . Just))
|