2021-09-20 03:32:02 -04:00
|
|
|
module Quox.Error
|
|
|
|
|
2022-04-27 08:55:19 -04:00
|
|
|
import public Data.List.Elem
|
2021-09-26 04:55:07 -04:00
|
|
|
|
2022-04-26 12:17:59 -04:00
|
|
|
import public Control.Monad.Identity
|
2021-09-20 03:32:02 -04:00
|
|
|
import Control.Monad.Trans
|
|
|
|
import Control.Monad.Reader
|
|
|
|
import Control.Monad.Writer
|
|
|
|
import Control.Monad.State
|
|
|
|
import Control.Monad.RWS
|
|
|
|
|
|
|
|
%default total
|
|
|
|
|
|
|
|
|
2021-12-23 10:05:55 -05:00
|
|
|
||| a representation of a list's length. this is used in `implyAll` to transform
|
|
|
|
||| the constraints one by one
|
2021-09-20 03:32:02 -04:00
|
|
|
public export
|
|
|
|
data Spine : List a -> Type where
|
|
|
|
NIL : Spine []
|
|
|
|
CONS : Spine xs -> Spine (x :: xs)
|
|
|
|
%builtin Natural Spine
|
|
|
|
|
|
|
|
|
2021-09-25 14:13:13 -04:00
|
|
|
||| if `types` is a `List Type`, then `OneOf types` is a value of one of them.
|
|
|
|
||| (along with a pointer to which type it is.)
|
2021-09-20 03:32:02 -04:00
|
|
|
public export
|
|
|
|
record OneOf types where
|
|
|
|
constructor One
|
|
|
|
elem : type `Elem` types
|
|
|
|
1 value : type
|
2021-09-26 04:55:07 -04:00
|
|
|
-- this is basically the same as Data.OpenUnion, but using Elem instead of
|
|
|
|
-- AtIndex is much easier for some stuff here e.g. `get`
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
export
|
|
|
|
Uninhabited (OneOf []) where uninhabited x = uninhabited x.elem
|
|
|
|
|
|
|
|
|
|
|
|
export %inline
|
2022-04-07 18:14:05 -04:00
|
|
|
one : ty `Elem` types => ty -> OneOf types
|
2022-02-26 19:28:49 -05:00
|
|
|
one @{elem} value = One {elem, value}
|
2021-09-20 03:32:02 -04:00
|
|
|
|
2021-09-25 14:13:13 -04:00
|
|
|
||| `All p types` computes a constraint for `p a` for each `a` in `types`
|
2021-09-20 03:32:02 -04:00
|
|
|
public export
|
|
|
|
All : (Type -> Type) -> List Type -> Type
|
2021-12-23 10:05:55 -05:00
|
|
|
All p = foldr (,) () . map p
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
eq : All Eq types => OneOf types -> OneOf types -> Bool
|
|
|
|
eq (One Here x) (One Here y) = x == y
|
|
|
|
eq (One (There p) x) (One (There q) y) = eq (One p x) (One q y)
|
|
|
|
eq (One Here _) (One (There _) _) = False
|
2021-12-23 10:05:55 -05:00
|
|
|
eq (One (There _) _) (One Here _) = False
|
2021-09-20 03:32:02 -04:00
|
|
|
|
2021-09-25 14:13:13 -04:00
|
|
|
export %inline
|
2021-09-20 03:32:02 -04:00
|
|
|
All Eq types => Eq (OneOf types) where (==) = eq
|
|
|
|
|
|
|
|
|
2021-12-23 10:05:55 -05:00
|
|
|
export
|
|
|
|
implyAll : (0 c, d : Type -> Type) ->
|
|
|
|
(forall a. c a -> d a) => Spine types => All c types => All d types
|
|
|
|
implyAll c d @{q} @{spine} @{ps} = go spine ps where
|
|
|
|
go : forall types. Spine types -> All c types -> All d types
|
|
|
|
go NIL _ = ()
|
|
|
|
go (CONS tl) (p, ps) = (q p, go tl ps)
|
|
|
|
|
2021-09-20 03:32:02 -04:00
|
|
|
|
2021-09-25 14:13:13 -04:00
|
|
|
private %inline
|
2021-09-20 03:32:02 -04:00
|
|
|
[eqOrds] (Spine types, All Ord types) => Eq (OneOf types) where
|
2021-12-23 10:05:55 -05:00
|
|
|
(==) = eq @{implyAll Ord Eq}
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
|
|
|
|
private
|
2021-12-23 10:05:55 -05:00
|
|
|
cmp : All Ord types => (x, y : OneOf types) -> Ordering
|
2021-09-20 03:32:02 -04:00
|
|
|
cmp (One Here x) (One Here y) = compare x y
|
|
|
|
cmp (One Here _) (One (There _) _) = LT
|
|
|
|
cmp (One (There _) _) (One Here _) = GT
|
|
|
|
cmp (One (There p) x) (One (There q) y) = cmp (One p x) (One q y)
|
|
|
|
|
2021-09-25 14:13:13 -04:00
|
|
|
export %inline
|
2021-09-20 03:32:02 -04:00
|
|
|
(Spine types, All Ord types) => Ord (OneOf types) using eqOrds where
|
|
|
|
compare = cmp
|
|
|
|
|
|
|
|
|
2021-12-23 10:05:55 -05:00
|
|
|
export %inline
|
|
|
|
All Show types => Show (OneOf types) where
|
|
|
|
showPrec d = go where
|
|
|
|
go : forall types. All Show types => OneOf types -> String
|
|
|
|
go (One Here value) = showPrec d value
|
|
|
|
go (One (There p) value) = go $ One p value
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
|
|
|
|
public export
|
|
|
|
record ErrorT (errs : List Type) (m : Type -> Type) (res : Type) where
|
|
|
|
constructor MkErrorT
|
|
|
|
runErrorT : m (Either (OneOf errs) res)
|
|
|
|
|
|
|
|
public export
|
|
|
|
Error : List Type -> Type -> Type
|
|
|
|
Error errs = ErrorT errs Identity
|
|
|
|
|
|
|
|
export
|
|
|
|
runError : Error errs a -> Either (OneOf errs) a
|
|
|
|
runError = runIdentity . runErrorT
|
|
|
|
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
Functor m => Functor (ErrorT errs m) where
|
|
|
|
map f (MkErrorT act) = MkErrorT $ map (map f) act
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
Applicative m => Applicative (ErrorT errs m) where
|
|
|
|
pure = MkErrorT . pure . pure
|
|
|
|
MkErrorT mf <*> MkErrorT mx = MkErrorT [|mf <*> mx|]
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
Monad m => Monad (ErrorT errs m) where
|
|
|
|
MkErrorT act >>= k = MkErrorT $ act >>= either (pure . Left) (runErrorT . k)
|
|
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
without' : (xs : List a) -> x `Elem` xs -> List a
|
|
|
|
without' (_ :: xs) Here = xs
|
|
|
|
without' (y :: xs) (There p) = y :: without' xs p
|
|
|
|
|
|
|
|
infix 9 `without`
|
|
|
|
export %inline
|
|
|
|
without : (xs : List a) -> (x : a) -> x `Elem` xs => List a
|
2021-12-23 10:05:55 -05:00
|
|
|
(xs `without` x) @{e} = without' xs e
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
get' : err `Elem` errs -> OneOf errs -> Either err (OneOf (errs `without` err))
|
|
|
|
get' Here (One Here x) = Left x
|
|
|
|
get' Here (One (There p) x) = Right (One p x)
|
|
|
|
get' (There y) (One Here x) = Right (One Here x)
|
|
|
|
get' (There y) (One (There p) x) = mapSnd {elem $= There} $ get' y (One p x)
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
get : (0 err : Type) -> err `Elem` errs =>
|
|
|
|
OneOf errs -> Either err (OneOf (errs `without` err))
|
2021-12-23 10:05:55 -05:00
|
|
|
get _ @{e} = get' e
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
noErrorsT : Monad m => ErrorT [] m a -> m a
|
|
|
|
noErrorsT (MkErrorT act) = act >>= either absurd pure
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
noErrors : Error [] a -> a
|
|
|
|
noErrors = runIdentity . noErrorsT
|
|
|
|
|
|
|
|
|
|
|
|
public export
|
|
|
|
data Embed : List a -> List a -> Type where
|
|
|
|
Nil : Embed [] ys
|
|
|
|
(::) : x `Elem` ys -> Embed xs ys -> Embed (x::xs) ys
|
|
|
|
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
embedElem : Embed xs ys => x `Elem` xs -> x `Elem` ys
|
2021-12-23 10:05:55 -05:00
|
|
|
embedElem @{emb} = go emb where
|
|
|
|
go : forall xs. Embed xs ys -> x `Elem` xs -> x `Elem` ys
|
|
|
|
go (e :: _) Here = e
|
|
|
|
go (_ :: es) (There p) = go es p
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
(<|>) : Applicative m => ErrorT errs m a -> ErrorT errs m a -> ErrorT errs m a
|
|
|
|
MkErrorT act1 <|> MkErrorT act2 = MkErrorT [|act1 `or` act2|] where
|
|
|
|
or : Either l r -> Either l r -> Either l r
|
|
|
|
one `or` two = case one of Left err => two; Right x => pure x
|
|
|
|
|
|
|
|
|
|
|
|
public export
|
2021-09-25 14:13:13 -04:00
|
|
|
interface Monad m => MonadThrow err m where
|
|
|
|
throw : err -> m a
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
public export
|
2021-09-25 14:13:13 -04:00
|
|
|
interface MonadThrow err m1 => MonadCatch err m1 m2 | err, m1 where
|
2021-09-20 03:32:02 -04:00
|
|
|
catch : (act : m1 a) -> (catch : err -> m2 a) -> m2 a
|
|
|
|
|
|
|
|
public export
|
2021-09-25 14:13:13 -04:00
|
|
|
interface (Monad m1, Monad m2) => MonadEmbed m1 m2 where embed : m1 a -> m2 a
|
2021-09-20 03:32:02 -04:00
|
|
|
|
2022-04-23 18:21:30 -04:00
|
|
|
public export
|
|
|
|
MonadThrows : (errs : List Type) -> (m : Type -> Type) -> Type
|
|
|
|
MonadThrows [] m = Monad m
|
|
|
|
MonadThrows (ty :: tys) m = (MonadThrow ty m, MonadThrows tys m)
|
|
|
|
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
2021-09-25 14:13:13 -04:00
|
|
|
(Monad m, err `Elem` errs) =>
|
|
|
|
MonadThrow err (ErrorT errs m)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
2022-02-26 19:28:49 -05:00
|
|
|
throw = MkErrorT . pure . Left . one
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
|
|
|
(Monad m, err `Elem` errs) =>
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadCatch err (ErrorT errs m) (ErrorT (errs `without` err) m)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
|
|
|
catch (MkErrorT act) handler = MkErrorT $
|
|
|
|
act <&> mapFst (get err) >>= \case
|
|
|
|
Left (Left this) => runErrorT $ handler this
|
|
|
|
Left (Right other) => pure $ Left other
|
|
|
|
Right ok => pure $ Right ok
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
|
|
|
(Monad m, Embed errs1 errs2) =>
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadEmbed (ErrorT errs1 m) (ErrorT errs2 m)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
2021-12-23 10:05:55 -05:00
|
|
|
embed (MkErrorT act) = MkErrorT $ act <&> mapFst {elem $= embedElem}
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
MonadTrans (ErrorT errs) where lift = MkErrorT . map Right
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
MonadReader r m => MonadReader r (ErrorT errs m) where
|
|
|
|
local f (MkErrorT act) = MkErrorT $ local f act
|
|
|
|
ask = lift ask
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
MonadWriter w m => MonadWriter w (ErrorT errs m) where
|
|
|
|
tell = MkErrorT . map Right . tell
|
|
|
|
|
|
|
|
pass (MkErrorT act) = MkErrorT $ pass $ do
|
|
|
|
Right (res, f) <- act
|
|
|
|
| Left err => pure (Left err, id)
|
|
|
|
pure (Right res, f)
|
|
|
|
|
|
|
|
listen (MkErrorT act) = MkErrorT $ do
|
|
|
|
(res, x) <- listen act
|
|
|
|
pure $ mapSnd (,x) res
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
MonadState s m => MonadState s (ErrorT errs m) where
|
|
|
|
get = lift get
|
|
|
|
put = lift . put
|
|
|
|
state = lift . state
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
MonadRWS r w s m => MonadRWS r w s (ErrorT errs m) where
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
HasIO m => HasIO (ErrorT errs m) where
|
|
|
|
liftIO = MkErrorT . map Right . liftIO
|
|
|
|
|
|
|
|
|
|
|
|
export %inline
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadThrow err m => MonadThrow err (ReaderT r m) where throw = lift . throw
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
export %inline
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadThrow err m => MonadThrow err (WriterT w m) where throw = lift . throw
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
export %inline
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadThrow err m => MonadThrow err (StateT s m) where throw = lift . throw
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
export %inline
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadThrow err m => MonadThrow err (RWST r w s m) where throw = lift . throw
|
2021-09-20 03:32:02 -04:00
|
|
|
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadCatch err m1 m2 =>
|
|
|
|
MonadCatch err (ReaderT r m1) (ReaderT r m2)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
|
|
|
catch (MkReaderT act) handler = MkReaderT $ \r =>
|
|
|
|
act r `catch` runReaderT r . handler
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadCatch err m1 m2 =>
|
|
|
|
MonadCatch err (WriterT w m1) (WriterT w m2)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
|
|
|
catch (MkWriterT act) handler = MkWriterT $ \w =>
|
|
|
|
act w `catch` \e => unWriterT (handler e) w
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadCatch err m1 m2 =>
|
|
|
|
MonadCatch err (StateT s m1) (StateT s m2)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
|
|
|
catch (ST act) handler = ST $ \s =>
|
|
|
|
act s `catch` \e => runStateT' (handler e) s
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadCatch err m1 m2 =>
|
|
|
|
MonadCatch err (RWST r w s m1) (RWST r w s m2)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
|
|
|
catch (MkRWST act) handler = MkRWST $ \r, s, w =>
|
|
|
|
act r s w `catch` \e => unRWST (handler e) r s w
|
|
|
|
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadEmbed m1 m2 =>
|
|
|
|
MonadEmbed (ReaderT r m1) (ReaderT r m2)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
|
|
|
embed (MkReaderT act) = MkReaderT $ embed . act
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadEmbed m1 m2 =>
|
|
|
|
MonadEmbed (WriterT w m1) (WriterT w m2)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
|
|
|
embed (MkWriterT act) = MkWriterT $ embed . act
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadEmbed m1 m2 =>
|
|
|
|
MonadEmbed (StateT s m1) (StateT s m2)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
|
|
|
embed (ST act) = ST $ embed . act
|
|
|
|
|
|
|
|
export %inline
|
|
|
|
implementation
|
2021-09-25 14:13:13 -04:00
|
|
|
MonadEmbed m1 m2 =>
|
|
|
|
MonadEmbed (RWST r w s m1) (RWST r w s m2)
|
2021-09-20 03:32:02 -04:00
|
|
|
where
|
|
|
|
embed (MkRWST act) = MkRWST $ \r, s, w => embed $ act r s w
|