Make GhcMod a special case of GhcModT
i.e. turn GhcMod into a monad transformer
This commit is contained in:
parent
56ad1a3c8c
commit
320b2243a2
@ -1,14 +1,18 @@
|
|||||||
{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, FlexibleInstances #-}
|
{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, FlexibleInstances #-}
|
||||||
{-# LANGUAGE MultiParamTypeClasses, RankNTypes, TypeFamilies #-}
|
{-# LANGUAGE FlexibleContexts, MultiParamTypeClasses, RankNTypes #-}
|
||||||
|
{-# LANGUAGE TypeFamilies, UndecidableInstances #-}
|
||||||
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
||||||
|
|
||||||
module Language.Haskell.GhcMod.Monad (
|
module Language.Haskell.GhcMod.Monad (
|
||||||
GhcMod
|
GhcMod
|
||||||
|
, GhcModT
|
||||||
, GhcModEnv(..)
|
, GhcModEnv(..)
|
||||||
, GhcModWriter
|
, GhcModWriter
|
||||||
, GhcModState(..)
|
, GhcModState(..)
|
||||||
, runGhcMod'
|
, runGhcMod'
|
||||||
, runGhcMod
|
, runGhcMod
|
||||||
|
, runGhcModT'
|
||||||
|
, runGhcModT
|
||||||
, newGhcModEnv
|
, newGhcModEnv
|
||||||
, withErrorHandler
|
, withErrorHandler
|
||||||
, toGhcMod
|
, toGhcMod
|
||||||
@ -44,10 +48,13 @@ import Control.Monad.Trans.Class (lift)
|
|||||||
import Data.Monoid (Monoid)
|
import Data.Monoid (Monoid)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
import Control.Monad (liftM)
|
import Control.Applicative (Alternative)
|
||||||
|
import Control.Monad (MonadPlus, liftM)
|
||||||
import Control.Monad.Base (MonadBase,liftBase)
|
import Control.Monad.Base (MonadBase,liftBase)
|
||||||
|
|
||||||
import Control.Monad.Reader.Class
|
import Control.Monad.Reader.Class
|
||||||
import Control.Monad.State.Class
|
import Control.Monad.State.Class
|
||||||
|
import Control.Monad.Trans.Class
|
||||||
import Control.Monad.Trans.Control (MonadBaseControl(..), StM, liftBaseWith, control, liftBaseOp, liftBaseOp_)
|
import Control.Monad.Trans.Control (MonadBaseControl(..), StM, liftBaseWith, control, liftBaseOp, liftBaseOp_)
|
||||||
import Control.Monad.Trans.RWS.Lazy (RWST(..),runRWST)
|
import Control.Monad.Trans.RWS.Lazy (RWST(..),runRWST)
|
||||||
import Control.Monad.Writer.Class
|
import Control.Monad.Writer.Class
|
||||||
@ -73,16 +80,20 @@ defaultState = GhcModState
|
|||||||
type GhcModWriter = ()
|
type GhcModWriter = ()
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
type GhcMod a = GhcModT IO a
|
||||||
|
|
||||||
newtype GhcMod a = GhcMod {
|
newtype GhcModT m a = GhcModT {
|
||||||
unGhcMod :: RWST GhcModEnv GhcModWriter GhcModState IO a
|
unGhcModT :: RWST GhcModEnv GhcModWriter GhcModState m a
|
||||||
} deriving (Functor
|
} deriving (Functor
|
||||||
,Applicative
|
,Applicative
|
||||||
|
,Alternative
|
||||||
,Monad
|
,Monad
|
||||||
|
,MonadPlus
|
||||||
,MonadIO
|
,MonadIO
|
||||||
,MonadReader GhcModEnv
|
,MonadReader GhcModEnv
|
||||||
,MonadWriter GhcModWriter
|
,MonadWriter GhcModWriter
|
||||||
,MonadState GhcModState
|
,MonadState GhcModState
|
||||||
|
,MonadTrans
|
||||||
)
|
)
|
||||||
|
|
||||||
#if __GLASGOW_HASKELL__ < 708
|
#if __GLASGOW_HASKELL__ < 708
|
||||||
@ -92,13 +103,13 @@ instance (Monoid w, MonadIO m) => MonadIO (RWST r w s m) where
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
runGhcModT' :: (MonadIO m, MonadBaseControl IO m)
|
||||||
runGhcMod' :: GhcModEnv
|
=> GhcModEnv
|
||||||
-> GhcModState
|
-> GhcModState
|
||||||
-> GhcMod a
|
-> GhcModT m a
|
||||||
-> IO (a,(GhcModState, GhcModWriter))
|
-> m (a,(GhcModState, GhcModWriter))
|
||||||
runGhcMod' r s a = do
|
runGhcModT' r s a = do
|
||||||
(a', s',w) <- runRWST (unGhcMod $ initGhcMonad (Just libdir) >> a) r s
|
(a',s',w) <- runRWST (unGhcModT $ initGhcMonad (Just libdir) >> a) r s
|
||||||
return (a',(s',w))
|
return (a',(s',w))
|
||||||
|
|
||||||
newGhcModEnv :: Options -> FilePath -> IO GhcModEnv
|
newGhcModEnv :: Options -> FilePath -> IO GhcModEnv
|
||||||
@ -111,16 +122,24 @@ newGhcModEnv opt dir = do
|
|||||||
, gmCradle = c
|
, gmCradle = c
|
||||||
}
|
}
|
||||||
|
|
||||||
runGhcMod :: Options -> GhcMod a -> IO a
|
runGhcModT :: (MonadIO m, MonadBaseControl IO m) => Options -> GhcModT m a -> m a
|
||||||
runGhcMod opt action = do
|
runGhcModT opt action = do
|
||||||
env <- liftIO $ newGhcModEnv opt =<< getCurrentDirectory
|
env <- liftBase $ newGhcModEnv opt =<< getCurrentDirectory
|
||||||
(a,(_,_)) <- runGhcMod' env defaultState $ do
|
(a,(_,_)) <- runGhcModT' env defaultState $ do
|
||||||
dflags <- getSessionDynFlags
|
dflags <- getSessionDynFlags
|
||||||
defaultCleanupHandler dflags $ do
|
defaultCleanupHandler dflags $ do
|
||||||
toGhcMod $ initializeFlagsWithCradle opt (gmCradle env)
|
initializeFlagsWithCradle opt (gmCradle env)
|
||||||
action
|
action
|
||||||
return a
|
return a
|
||||||
|
|
||||||
|
runGhcMod' :: GhcModEnv
|
||||||
|
-> GhcModState
|
||||||
|
-> GhcModT IO a
|
||||||
|
-> IO (a,(GhcModState, GhcModWriter))
|
||||||
|
runGhcMod' = runGhcModT'
|
||||||
|
|
||||||
|
runGhcMod :: Options -> GhcMod a -> IO a
|
||||||
|
runGhcMod = runGhcModT
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
withErrorHandler :: String -> GhcMod a -> GhcMod a
|
withErrorHandler :: String -> GhcMod a -> GhcMod a
|
||||||
@ -133,7 +152,7 @@ withErrorHandler label = ghandle ignore
|
|||||||
exitSuccess
|
exitSuccess
|
||||||
|
|
||||||
-- | This is only a transitional mechanism don't use it for new code.
|
-- | This is only a transitional mechanism don't use it for new code.
|
||||||
toGhcMod :: Ghc a -> GhcMod a
|
toGhcMod :: (Functor m, MonadIO m) => Ghc a -> GhcModT m a
|
||||||
toGhcMod a = do
|
toGhcMod a = do
|
||||||
s <- gmGhcSession <$> ask
|
s <- gmGhcSession <$> ask
|
||||||
liftIO $ unGhc a $ Session s
|
liftIO $ unGhc a $ Session s
|
||||||
@ -146,30 +165,90 @@ options = gmOptions <$> ask
|
|||||||
cradle :: GhcMod Cradle
|
cradle :: GhcMod Cradle
|
||||||
cradle = gmCradle <$> ask
|
cradle = gmCradle <$> ask
|
||||||
|
|
||||||
instance MonadBase IO GhcMod where
|
|
||||||
liftBase = GhcMod . liftBase
|
|
||||||
|
|
||||||
instance MonadBaseControl IO GhcMod where
|
instance (MonadBaseControl IO m) => MonadBase IO (GhcModT m) where
|
||||||
newtype StM GhcMod a = StGhcMod {
|
liftBase = GhcModT . liftBase
|
||||||
unStGhcMod :: StM (RWST GhcModEnv () GhcModState IO) a }
|
|
||||||
|
|
||||||
liftBaseWith f = GhcMod . liftBaseWith $ \runInBase ->
|
instance (MonadBaseControl IO m) => MonadBaseControl IO (GhcModT m) where
|
||||||
f $ liftM StGhcMod . runInBase . unGhcMod
|
newtype StM (GhcModT m) a = StGhcMod {
|
||||||
|
unStGhcMod :: StM (RWST GhcModEnv () GhcModState m) a }
|
||||||
|
|
||||||
restoreM = GhcMod . restoreM . unStGhcMod
|
liftBaseWith f = GhcModT . liftBaseWith $ \runInBase ->
|
||||||
|
f $ liftM StGhcMod . runInBase . unGhcModT
|
||||||
|
|
||||||
|
restoreM = GhcModT . restoreM . unStGhcMod
|
||||||
{-# INLINE liftBaseWith #-}
|
{-# INLINE liftBaseWith #-}
|
||||||
{-# INLINE restoreM #-}
|
{-# INLINE restoreM #-}
|
||||||
|
|
||||||
instance GhcMonad GhcMod where
|
-- GHC cannot prove the following instances to be decidable automatically using
|
||||||
getSession = liftIO . readIORef . gmGhcSession =<< ask
|
-- the FlexibleContexts extension as they violate the second Paterson Condition,
|
||||||
setSession a = liftIO . flip writeIORef a . gmGhcSession =<< ask
|
-- namely that: The assertion has fewer constructors and variables (taken
|
||||||
|
-- together and counting repetitions) than the head. Specifically the
|
||||||
|
-- @MonadBaseControl IO m@ constraint is causing this violation.
|
||||||
|
--
|
||||||
|
-- Proof of termination:
|
||||||
|
--
|
||||||
|
-- Assuming all constraints containing the variable `m' exist and are decidable
|
||||||
|
-- we show termination by manually replacing the current set of constraints with
|
||||||
|
-- their own set of constraints and show that this, after a finite number of
|
||||||
|
-- steps, results in the empty set, i.e. not having to check any more
|
||||||
|
-- constraints.
|
||||||
|
--
|
||||||
|
-- We start by setting the constraints to be those immediate constraints of the
|
||||||
|
-- instance declaration which cannot be proven decidable automatically for the
|
||||||
|
-- type under consideration.
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- { MonadBaseControl IO m }
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- Classes used:
|
||||||
|
--
|
||||||
|
-- * @class MonadBase b m => MonadBaseControl b m@
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- { MonadBase IO m }
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- Classes used:
|
||||||
|
--
|
||||||
|
-- * @class (Applicative b, Applicative m, Monad b, Monad m) => MonadBase b m@
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- { Applicative IO, Applicative m, Monad IO, Monad m }
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- Classes used:
|
||||||
|
--
|
||||||
|
-- * @class Monad m@
|
||||||
|
-- * @class Applicative f => Functor f@
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- { Functor m }
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- Classes used:
|
||||||
|
--
|
||||||
|
-- * @class Functor f@
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- { }
|
||||||
|
-- @
|
||||||
|
-- ∎
|
||||||
|
|
||||||
|
instance (Functor m, MonadIO m, MonadBaseControl IO m)
|
||||||
|
=> GhcMonad (GhcModT m) where
|
||||||
|
getSession = (liftIO . readIORef) . gmGhcSession =<< ask
|
||||||
|
setSession a = (liftIO . flip writeIORef a) . gmGhcSession =<< ask
|
||||||
|
|
||||||
#if __GLASGOW_HASKELL__ >= 706
|
#if __GLASGOW_HASKELL__ >= 706
|
||||||
instance HasDynFlags GhcMod where
|
instance (Functor m, MonadIO m, MonadBaseControl IO m)
|
||||||
|
=> HasDynFlags (GhcModT m) where
|
||||||
getDynFlags = getSessionDynFlags
|
getDynFlags = getSessionDynFlags
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
instance ExceptionMonad GhcMod where
|
instance (MonadIO m, MonadBaseControl IO m)
|
||||||
|
=> ExceptionMonad (GhcModT m) where
|
||||||
gcatch act handler = control $ \run ->
|
gcatch act handler = control $ \run ->
|
||||||
run act `gcatch` (run . handler)
|
run act `gcatch` (run . handler)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user