-- |
-- Using bijections with monads.
{-# LANGUAGE Safe, TypeOperators #-}
module Data.Invertible.Monad
  ( bind
  , (=<<->>=)
  , liftM
  ) where

import qualified Control.Monad as M

import Data.Invertible.Bijection

-- |Bind two functions to create a "Control.Invertible.MonadArrow"-form bijection.
bind :: Monad m => (a -> m b) -> (b -> m a) -> m a <-> m b
bind :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> (b -> m a) -> m a <-> m b
bind a -> m b
f b -> m a
g = (a -> m b
f forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) forall (a :: * -> * -> *) b c. a b c -> a c b -> Bijection a b c
:<->: (b -> m a
g forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<)

-- |Crazy operator form of 'bind'.
(=<<->>=) :: Monad m => (a -> m b) -> (b -> m a) -> m a <-> m b
=<<->>= :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> (b -> m a) -> m a <-> m b
(=<<->>=) = forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> (b -> m a) -> m a <-> m b
bind

infix 2 =<<->>=

-- |Promote a bijection to a "Control.Invertible.MonadArrow"-form bijection.
-- (Equivalent to 'Data.Invertible.Functor.bifmap' and 'Control.Invertible.BiArrow.biarr'.)
liftM :: Monad m => a <-> b -> m a <-> m b
liftM :: forall (m :: * -> *) a b. Monad m => (a <-> b) -> m a <-> m b
liftM (a -> b
f :<->: b -> a
g) = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
M.liftM a -> b
f forall (a :: * -> * -> *) b c. a b c -> a c b -> Bijection a b c
:<->: forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
M.liftM b -> a
g