1{-# LANGUAGE RankNTypes #-} 2-- | Please see the README.md file for information on using this 3-- package at <https://www.stackage.org/package/unliftio-core>. 4module Control.Monad.IO.Unlift 5 ( MonadUnliftIO (..) 6 , UnliftIO (..) 7 , askUnliftIO 8 , askRunInIO 9 , withUnliftIO 10 , toIO 11 , wrappedWithRunInIO 12 , MonadIO (..) 13 ) where 14 15import Control.Monad.IO.Class 16import Control.Monad.Trans.Reader (ReaderT (..)) 17import Control.Monad.Trans.Identity (IdentityT (..)) 18 19-- | The ability to run any monadic action @m a@ as @IO a@. 20-- 21-- This is more precisely a natural transformation. We need to new 22-- datatype (instead of simply using a @forall@) due to lack of 23-- support in GHC for impredicative types. 24-- 25-- @since 0.1.0.0 26newtype UnliftIO m = UnliftIO { unliftIO :: forall a. m a -> IO a } 27 28-- | Monads which allow their actions to be run in 'IO'. 29-- 30-- While 'MonadIO' allows an 'IO' action to be lifted into another 31-- monad, this class captures the opposite concept: allowing you to 32-- capture the monadic context. Note that, in order to meet the laws 33-- given below, the intuition is that a monad must have no monadic 34-- state, but may have monadic context. This essentially limits 35-- 'MonadUnliftIO' to 'ReaderT' and 'IdentityT' transformers on top of 36-- 'IO'. 37-- 38-- Laws. For any value @u@ returned by 'askUnliftIO', it must meet the 39-- monad transformer laws as reformulated for @MonadUnliftIO@: 40-- 41-- * @unliftIO u . return = return@ 42-- 43-- * @unliftIO u (m >>= f) = unliftIO u m >>= unliftIO u . f@ 44-- 45-- Instances of @MonadUnliftIO@ must also satisfy the idempotency law: 46-- 47-- * @askUnliftIO >>= \\u -> (liftIO . unliftIO u) m = m@ 48-- 49-- This law showcases two properties. First, 'askUnliftIO' doesn't change 50-- the monadic context, and second, @liftIO . unliftIO u@ is equivalent to 51-- @id@ IF called in the same monadic context as 'askUnliftIO'. 52-- 53-- @since 0.1.0.0 54class MonadIO m => MonadUnliftIO m where 55 -- | Convenience function for capturing the monadic context and running an 'IO' 56 -- action with a runner function. The runner function is used to run a monadic 57 -- action @m@ in @IO@. 58 -- 59 -- @since 0.1.0.0 60 withRunInIO :: ((forall a. m a -> IO a) -> IO b) -> m b 61instance MonadUnliftIO IO where 62 {-# INLINE withRunInIO #-} 63 withRunInIO inner = inner id 64instance MonadUnliftIO m => MonadUnliftIO (ReaderT r m) where 65 {-# INLINE withRunInIO #-} 66 withRunInIO inner = 67 ReaderT $ \r -> 68 withRunInIO $ \run -> 69 inner (run . flip runReaderT r) 70 71instance MonadUnliftIO m => MonadUnliftIO (IdentityT m) where 72 {-# INLINE withRunInIO #-} 73 withRunInIO inner = 74 IdentityT $ 75 withRunInIO $ \run -> 76 inner (run . runIdentityT) 77 78-- | Capture the current monadic context, providing the ability to 79-- run monadic actions in 'IO'. 80-- 81-- See 'UnliftIO' for an explanation of why we need a helper 82-- datatype here. 83-- 84-- Prior to version 0.2.0.0 of this library, this was a method in the 85-- 'MonadUnliftIO' type class. It was moved out due to 86-- <https://github.com/fpco/unliftio/issues/55>. 87-- 88-- @since 0.1.0.0 89askUnliftIO :: MonadUnliftIO m => m (UnliftIO m) 90askUnliftIO = withRunInIO (\run -> return (UnliftIO run)) 91{-# INLINE askUnliftIO #-} 92-- Would be better, but GHC hates us 93-- askUnliftIO :: m (forall a. m a -> IO a) 94 95 96-- | Same as 'askUnliftIO', but returns a monomorphic function 97-- instead of a polymorphic newtype wrapper. If you only need to apply 98-- the transformation on one concrete type, this function can be more 99-- convenient. 100-- 101-- @since 0.1.0.0 102{-# INLINE askRunInIO #-} 103askRunInIO :: MonadUnliftIO m => m (m a -> IO a) 104-- withRunInIO return would be nice, but GHC 7.8.4 doesn't like it 105askRunInIO = withRunInIO (\run -> (return (\ma -> run ma))) 106 107-- | Convenience function for capturing the monadic context and running 108-- an 'IO' action. The 'UnliftIO' newtype wrapper is rarely needed, so 109-- prefer 'withRunInIO' to this function. 110-- 111-- @since 0.1.0.0 112{-# INLINE withUnliftIO #-} 113withUnliftIO :: MonadUnliftIO m => (UnliftIO m -> IO a) -> m a 114withUnliftIO inner = askUnliftIO >>= liftIO . inner 115 116-- | Convert an action in @m@ to an action in @IO@. 117-- 118-- @since 0.1.0.0 119{-# INLINE toIO #-} 120toIO :: MonadUnliftIO m => m a -> m (IO a) 121toIO m = withRunInIO $ \run -> return $ run m 122 123{- | A helper function for implementing @MonadUnliftIO@ instances. 124Useful for the common case where you want to simply delegate to the 125underlying transformer. 126 127@since 0.1.2.0 128==== __Example__ 129 130> newtype AppT m a = AppT { unAppT :: ReaderT Int (ResourceT m) a } 131> deriving (Functor, Applicative, Monad, MonadIO) 132> -- Unfortunately, deriving MonadUnliftIO does not work. 133> 134> instance MonadUnliftIO m => MonadUnliftIO (AppT m) where 135> withRunInIO = wrappedWithRunInIO AppT unAppT 136-} 137{-# INLINE wrappedWithRunInIO #-} 138wrappedWithRunInIO :: MonadUnliftIO n 139 => (n b -> m b) 140 -- ^ The wrapper, for instance @IdentityT@. 141 -> (forall a. m a -> n a) 142 -- ^ The inverse, for instance @runIdentityT@. 143 -> ((forall a. m a -> IO a) -> IO b) 144 -- ^ The actual function to invoke 'withRunInIO' with. 145 -> m b 146wrappedWithRunInIO wrap unwrap inner = wrap $ withRunInIO $ \run -> 147 inner $ run . unwrap 148