{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneKindSignatures #-}

module GHC.Utils.Monad.Codensity
  ( Codensity(..), toCodensity, fromCodensity )
  where

import Data.Kind ( Type )

import GHC.Prelude
import GHC.Exts ( oneShot )

import Control.Monad.Fix
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Control.Concurrent.MVar ( newEmptyMVar, readMVar, putMVar )
import Control.Exception
import GHC.IO.Exception
import GHC.IO.Unsafe ( unsafeDupableInterleaveIO )

--------------------------------------------------------------------------------

type Codensity :: (Type -> Type) -> Type -> Type
newtype Codensity m a = Codensity { forall (m :: * -> *) a.
Codensity m a -> forall r. (a -> m r) -> m r
runCodensity :: forall r. (a -> m r) -> m r }
instance Functor (Codensity k) where
  fmap :: forall a b. (a -> b) -> Codensity k a -> Codensity k b
fmap a -> b
f (Codensity forall r. (a -> k r) -> k r
m) = (forall r. (b -> k r) -> k r) -> Codensity k b
forall (m :: * -> *) a.
(forall r. (a -> m r) -> m r) -> Codensity m a
Codensity ((forall r. (b -> k r) -> k r) -> Codensity k b)
-> (forall r. (b -> k r) -> k r) -> Codensity k b
forall a b. (a -> b) -> a -> b
$ ((b -> k r) -> k r) -> (b -> k r) -> k r
forall a b. (a -> b) -> a -> b
oneShot (\b -> k r
k -> (a -> k r) -> k r
forall r. (a -> k r) -> k r
m ((a -> k r) -> k r) -> (a -> k r) -> k r
forall a b. (a -> b) -> a -> b
$ (a -> k r) -> a -> k r
forall a b. (a -> b) -> a -> b
oneShot (\a
x -> b -> k r
k (b -> k r) -> b -> k r
forall a b. (a -> b) -> a -> b
$ a -> b
f a
x))
  {-# INLINE fmap #-}
instance Applicative (Codensity f) where
  pure :: forall a. a -> Codensity f a
pure a
x = (forall r. (a -> f r) -> f r) -> Codensity f a
forall (m :: * -> *) a.
(forall r. (a -> m r) -> m r) -> Codensity m a
Codensity ((forall r. (a -> f r) -> f r) -> Codensity f a)
-> (forall r. (a -> f r) -> f r) -> Codensity f a
forall a b. (a -> b) -> a -> b
$ ((a -> f r) -> f r) -> (a -> f r) -> f r
forall a b. (a -> b) -> a -> b
oneShot (\a -> f r
k -> a -> f r
k a
x)
  {-# INLINE pure #-}
  Codensity forall r. ((a -> b) -> f r) -> f r
f <*> :: forall a b. Codensity f (a -> b) -> Codensity f a -> Codensity f b
<*> Codensity forall r. (a -> f r) -> f r
g =
    (forall r. (b -> f r) -> f r) -> Codensity f b
forall (m :: * -> *) a.
(forall r. (a -> m r) -> m r) -> Codensity m a
Codensity ((forall r. (b -> f r) -> f r) -> Codensity f b)
-> (forall r. (b -> f r) -> f r) -> Codensity f b
forall a b. (a -> b) -> a -> b
$ ((b -> f r) -> f r) -> (b -> f r) -> f r
forall a b. (a -> b) -> a -> b
oneShot (\b -> f r
bfr -> ((a -> b) -> f r) -> f r
forall r. ((a -> b) -> f r) -> f r
f (((a -> b) -> f r) -> f r) -> ((a -> b) -> f r) -> f r
forall a b. (a -> b) -> a -> b
$ ((a -> b) -> f r) -> (a -> b) -> f r
forall a b. (a -> b) -> a -> b
oneShot (\a -> b
ab -> (a -> f r) -> f r
forall r. (a -> f r) -> f r
g ((a -> f r) -> f r) -> (a -> f r) -> f r
forall a b. (a -> b) -> a -> b
$ (a -> f r) -> a -> f r
forall a b. (a -> b) -> a -> b
oneShot (\a
x -> b -> f r
bfr (a -> b
ab a
x))))
  {-# INLINE (<*>) #-}
instance Monad (Codensity f) where
  return :: forall a. a -> Codensity f a
return = a -> Codensity f a
forall a. a -> Codensity f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
  {-# INLINE return #-}
  Codensity f a
m >>= :: forall a b. Codensity f a -> (a -> Codensity f b) -> Codensity f b
>>= a -> Codensity f b
k =
    (forall r. (b -> f r) -> f r) -> Codensity f b
forall (m :: * -> *) a.
(forall r. (a -> m r) -> m r) -> Codensity m a
Codensity ((forall r. (b -> f r) -> f r) -> Codensity f b)
-> (forall r. (b -> f r) -> f r) -> Codensity f b
forall a b. (a -> b) -> a -> b
$ ((b -> f r) -> f r) -> (b -> f r) -> f r
forall a b. (a -> b) -> a -> b
oneShot (\b -> f r
c -> Codensity f a -> forall r. (a -> f r) -> f r
forall (m :: * -> *) a.
Codensity m a -> forall r. (a -> m r) -> m r
runCodensity Codensity f a
m ((a -> f r) -> f r) -> (a -> f r) -> f r
forall a b. (a -> b) -> a -> b
$ (a -> f r) -> a -> f r
forall a b. (a -> b) -> a -> b
oneShot (\a
a -> Codensity f b -> forall r. (b -> f r) -> f r
forall (m :: * -> *) a.
Codensity m a -> forall r. (a -> m r) -> m r
runCodensity (a -> Codensity f b
k a
a) b -> f r
c))
  {-# INLINE (>>=) #-}
instance MonadTrans Codensity where
  lift :: forall (m :: * -> *) a. Monad m => m a -> Codensity m a
lift m a
m = (forall r. (a -> m r) -> m r) -> Codensity m a
forall (m :: * -> *) a.
(forall r. (a -> m r) -> m r) -> Codensity m a
Codensity ((forall r. (a -> m r) -> m r) -> Codensity m a)
-> (forall r. (a -> m r) -> m r) -> Codensity m a
forall a b. (a -> b) -> a -> b
$ ((a -> m r) -> m r) -> (a -> m r) -> m r
forall a b. (a -> b) -> a -> b
oneShot (m a
m m a -> (a -> m r) -> m r
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=)
  {-# INLINE lift #-}
instance MonadIO m => MonadIO (Codensity m) where
  liftIO :: forall a. IO a -> Codensity m a
liftIO = m a -> Codensity m a
forall (m :: * -> *) a. Monad m => m a -> Codensity m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> Codensity m a) -> (IO a -> m a) -> IO a -> Codensity m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> m a
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO
  {-# INLINE liftIO #-}
instance MonadIO m => MonadFix (Codensity m) where
  mfix :: forall a. (a -> Codensity m a) -> Codensity m a
mfix a -> Codensity m a
f = (forall r. (a -> m r) -> m r) -> Codensity m a
forall (m :: * -> *) a.
(forall r. (a -> m r) -> m r) -> Codensity m a
Codensity ((forall r. (a -> m r) -> m r) -> Codensity m a)
-> (forall r. (a -> m r) -> m r) -> Codensity m a
forall a b. (a -> b) -> a -> b
$ ((a -> m r) -> m r) -> (a -> m r) -> m r
forall a b. (a -> b) -> a -> b
oneShot (((a -> m r) -> m r) -> (a -> m r) -> m r)
-> ((a -> m r) -> m r) -> (a -> m r) -> m r
forall a b. (a -> b) -> a -> b
$ \ a -> m r
k -> do
    MVar a
promise <- IO (MVar a) -> m (MVar a)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (MVar a) -> m (MVar a)) -> IO (MVar a) -> m (MVar a)
forall a b. (a -> b) -> a -> b
$ IO (MVar a)
forall a. IO (MVar a)
newEmptyMVar
    a
ans     <- IO a -> m a
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> m a) -> IO a -> m a
forall a b. (a -> b) -> a -> b
$ IO a -> IO a
forall a. IO a -> IO a
unsafeDupableInterleaveIO
                      (IO a -> IO a) -> IO a -> IO a
forall a b. (a -> b) -> a -> b
$ MVar a -> IO a
forall a. MVar a -> IO a
readMVar MVar a
promise
                          IO a -> (BlockedIndefinitelyOnMVar -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch`
                        (\ BlockedIndefinitelyOnMVar
BlockedIndefinitelyOnMVar -> FixIOException -> IO a
forall e a. Exception e => e -> IO a
throwIO FixIOException
FixIOException)
    Codensity m a -> forall r. (a -> m r) -> m r
forall (m :: * -> *) a.
Codensity m a -> forall r. (a -> m r) -> m r
runCodensity (a -> Codensity m a
f a
ans) ((a -> m r) -> m r) -> (a -> m r) -> m r
forall a b. (a -> b) -> a -> b
$ (a -> m r) -> a -> m r
forall a b. (a -> b) -> a -> b
oneShot ((a -> m r) -> a -> m r) -> (a -> m r) -> a -> m r
forall a b. (a -> b) -> a -> b
$ \ a
a -> do
      IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ MVar a -> a -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar a
promise a
a
      a -> m r
k a
a
  {-# INLINE mfix #-}

toCodensity :: Monad m => m a -> Codensity m a
toCodensity :: forall (m :: * -> *) a. Monad m => m a -> Codensity m a
toCodensity m a
m = (forall r. (a -> m r) -> m r) -> Codensity m a
forall (m :: * -> *) a.
(forall r. (a -> m r) -> m r) -> Codensity m a
Codensity ((forall r. (a -> m r) -> m r) -> Codensity m a)
-> (forall r. (a -> m r) -> m r) -> Codensity m a
forall a b. (a -> b) -> a -> b
$ ((a -> m r) -> m r) -> (a -> m r) -> m r
forall a b. (a -> b) -> a -> b
oneShot (m a
m m a -> (a -> m r) -> m r
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=)
{-# INLINE toCodensity #-}

fromCodensity :: Monad m => Codensity m a -> m a
fromCodensity :: forall (m :: * -> *) a. Monad m => Codensity m a -> m a
fromCodensity Codensity m a
c = Codensity m a -> forall r. (a -> m r) -> m r
forall (m :: * -> *) a.
Codensity m a -> forall r. (a -> m r) -> m r
runCodensity Codensity m a
c a -> m a
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return
{-# INLINE fromCodensity #-}