{-# LANGUAGE AllowAmbiguousTypes #-}

-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.

{- |
Copyright   :  (c) 2023 Yamada Ryo
License     :  MPL-2.0 (see the file LICENSE)
Maintainer  :  ymdfield@outlook.jp
Stability   :  experimental
Portability :  portable
-}
module Data.Effect.Except where

data Throw e (a :: Type) where
    Throw :: e -> Throw e a

data Catch e f (a :: Type) where
    Catch :: f a -> (e -> f a) -> Catch e f a

makeEffect [''Throw] [''Catch]

liftEither :: (Throw e <: f, Applicative f) => Either e a -> f a
liftEither :: forall e (f :: * -> *) a.
(Throw e <: f, Applicative f) =>
Either e a -> f a
liftEither = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e a (f :: * -> *). SendIns (Throw e) f => e -> f a
throw forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# INLINE liftEither #-}

joinEither :: (Throw e <: m, Monad m) => m (Either e a) -> m a
joinEither :: forall e (m :: * -> *) a.
(Throw e <: m, Monad m) =>
m (Either e a) -> m a
joinEither = (forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e a (f :: * -> *). SendIns (Throw e) f => e -> f a
throw forall (f :: * -> *) a. Applicative f => a -> f a
pure)
{-# INLINE joinEither #-}

joinExcept :: Monad m => Either (m a) a -> m a
joinExcept :: forall (m :: * -> *) a. Monad m => Either (m a) a -> m a
joinExcept = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall a. a -> a
id forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# INLINE joinExcept #-}

exc :: Monad m => m (Either (m a) a) -> m a
exc :: forall (m :: * -> *) a. Monad m => m (Either (m a) a) -> m a
exc = (forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall a. a -> a
id forall (f :: * -> *) a. Applicative f => a -> f a
pure)
{-# INLINE exc #-}

withExcept :: (Catch e <<: f, Throw e <: f, Applicative f) => f a -> (e -> f ()) -> f a
withExcept :: forall e (f :: * -> *) a.
(Catch e <<: f, Throw e <: f, Applicative f) =>
f a -> (e -> f ()) -> f a
withExcept f a
thing e -> f ()
after = f a
thing forall a e (f :: * -> *).
SendSig (Catch e) f =>
f a -> (e -> f a) -> f a
`catch` \e
e -> e -> f ()
after e
e forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall e a (f :: * -> *). SendIns (Throw e) f => e -> f a
throw e
e
{-# INLINE withExcept #-}

onExcept :: forall e f a. (Catch e <<: f, Throw e <: f, Applicative f) => f a -> f () -> f a
onExcept :: forall e (f :: * -> *) a.
(Catch e <<: f, Throw e <: f, Applicative f) =>
f a -> f () -> f a
onExcept f a
thing f ()
after = f a
thing forall e (f :: * -> *) a.
(Catch e <<: f, Throw e <: f, Applicative f) =>
f a -> (e -> f ()) -> f a
`withExcept` \(e
_ :: e) -> f ()
after
{-# INLINE onExcept #-}