module Language.Haskell.TH.TypeGraph.TypeGraph
( TypeGraph, graph, gsimple, stack
, makeTypeGraph
, graphFromMap
, allPathNodes
, allPathStarts
, lensKeys, allLensKeys
, pathKeys, allPathKeys
, reachableFrom
, reachableFromSimple
, goalReachableFull
, goalReachableSimple
, goalReachableSimple'
, VertexStatus(..)
, adjacent
, typeGraphVertex
, typeGraphVertexOfField
) where
#if __GLASGOW_HASKELL__ < 709
import Control.Applicative
import Data.Monoid (mempty)
#else
import Control.Applicative
#endif
import Control.Lens
import Control.Monad (foldM)
import qualified Control.Monad.Reader as MTL (ask, ReaderT, runReaderT)
import Control.Monad.Readers (MonadReaders(askPoly, localPoly))
import Control.Monad.States (MonadStates)
import Control.Monad.Trans (lift)
import Data.Default (Default(def))
import Data.Foldable as Fold
import Data.Graph hiding (edges)
import Data.List as List (map)
import Data.Map.Strict as Map (insertWith, Map)
import qualified Data.Map.Strict as Map (toList)
import Data.Maybe (fromJust, mapMaybe)
import Data.Set.Extra as Set (empty, fromList, map, Set, singleton, toList, union, unions)
import Data.Traversable as Traversable
import Language.Haskell.Exts.Syntax ()
import Language.Haskell.TH
import Language.Haskell.TH.Desugar (DsMonad)
import Language.Haskell.TH.Instances ()
import Language.Haskell.TH.PprLib (ptext, vcat)
import Language.Haskell.TH.Syntax (Quasi(..))
import Language.Haskell.TH.TypeGraph.Edges (GraphEdges, simpleEdges)
import Language.Haskell.TH.TypeGraph.Expand (E(E), ExpandMap, expandType)
import Language.Haskell.TH.TypeGraph.Prelude (adjacent', reachable')
import Language.Haskell.TH.TypeGraph.TypeInfo (startTypes, TypeInfo, typeVertex', fieldVertex)
import Language.Haskell.TH.TypeGraph.Stack (StackElement)
import Language.Haskell.TH.TypeGraph.Vertex (TGV, TGVSimple, tgv, vsimple, TypeGraphVertex, etype)
import Prelude hiding (any, concat, concatMap, elem, exp, foldr, mapM_, null, or)
data TypeGraph
= TypeGraph
{ _graph :: (Graph, Vertex -> ((), TGV, [TGV]), TGV -> Maybe Vertex)
, _gsimple :: (Graph, Vertex -> ((), TGVSimple, [TGVSimple]), TGVSimple -> Maybe Vertex)
, _stack :: [StackElement]
}
makeTypeGraph :: MonadReaders TypeInfo m => (GraphEdges TGV) -> m TypeGraph
makeTypeGraph es = do
return $ TypeGraph
{ _graph = graphFromMap es
, _gsimple = graphFromMap (simpleEdges es)
, _stack = []
}
graphFromMap :: forall key. (Ord key) =>
GraphEdges key -> (Graph, Vertex -> ((), key, [key]), key -> Maybe Vertex)
graphFromMap mp =
graphFromEdges triples
where
triples :: [((), key, [key])]
triples = List.map (\ (k, ks) -> ((), k, Fold.toList ks)) $ Map.toList mp
$(makeLenses ''TypeGraph)
instance (Monad m, MonadReaders [StackElement] m) => MonadReaders [StackElement] (MTL.ReaderT TypeGraph m) where
askPoly = lift askPoly
localPoly f action = MTL.ask >>= MTL.runReaderT (localPoly f (lift action))
instance MonadReaders TypeInfo m => MonadReaders TypeInfo (MTL.ReaderT TypeGraph m) where
askPoly = lift askPoly
localPoly f action = MTL.ask >>= MTL.runReaderT (localPoly f (lift action))
instance Ppr Vertex where
ppr n = ptext ("V" ++ show n)
instance Ppr (Graph, Vertex -> ((), TGV, [TGV]), TGV -> Maybe Vertex) where
ppr (g, vf, _) = vcat (List.map (ppr . vf) (vertices g))
instance Ppr (Graph, Vertex -> ((), TGVSimple, [TGVSimple]), TGVSimple -> Maybe Vertex) where
ppr (g, vf, _) = vcat (List.map (ppr . vf) (vertices g))
allPathNodes :: forall m. (DsMonad m, MonadStates ExpandMap m, MonadReaders TypeGraph m, MonadReaders TypeInfo m) => m (Set TGV)
allPathNodes = do
(g, vf, kf) <- askPoly >>= return . view graph
kernel <- askPoly >>= \ti -> MTL.runReaderT (Traversable.mapM expandType (view startTypes ti) >>= Traversable.mapM typeVertex') ti
let keep = Set.fromList $ concatMap (reachable g) (mapMaybe kf kernel)
keep' = Set.map (view _2) . Set.map vf $ keep
return keep'
allPathStarts :: forall m. (DsMonad m, MonadStates ExpandMap m, MonadReaders TypeGraph m, MonadReaders TypeInfo m) => m (Set TGVSimple)
allPathStarts = Set.map (view vsimple) <$> allPathNodes
view' :: MonadReaders s m => Getting b s b -> m b
view' lns = view lns <$> askPoly
allLensKeys :: (DsMonad m, MonadStates ExpandMap m, MonadReaders TypeGraph m, MonadReaders TypeInfo m) => m (Map TGVSimple (Set TGV))
allLensKeys = do
starts <- Set.toList <$> allPathStarts
foldM (\mp s -> lensKeys s >>= return . Fold.foldr (Map.insertWith Set.union s . Set.singleton) mp) mempty starts
lensKeys :: (DsMonad m, MonadStates ExpandMap m, MonadReaders TypeGraph m, MonadReaders TypeInfo m) => TGVSimple -> m (Set TGV)
lensKeys x = do
g <- view' graph
return $ Set.fromList $ adjacent' g (tgv x)
allPathKeys :: (DsMonad m, MonadStates ExpandMap m, MonadReaders TypeGraph m, MonadReaders TypeInfo m) => m (Map TGVSimple (Set TGVSimple))
allPathKeys = do
starts <- Set.toList <$> allPathStarts
foldM (\mp s -> pathKeys s >>= return . Fold.foldr (Map.insertWith Set.union s . Set.singleton) mp) mempty starts
pathKeys :: (DsMonad m, MonadStates ExpandMap m, MonadReaders TypeGraph m, MonadReaders TypeInfo m) => TGVSimple -> m (Set TGVSimple)
pathKeys x = do
gs <- view' gsimple
return $ Set.fromList $ reachable' gs x
reachableFrom :: forall m. (DsMonad m, MonadReaders TypeGraph m) => TGV -> m (Set TGV)
reachableFrom v = do
(g, vf, kf) <- view' graph
case kf v of
Nothing -> return Set.empty
Just v' -> return $ Set.map (\(_, key, _) -> key) . Set.map vf $ Set.fromList $ reachable (transposeG g) v'
reachableFromSimple :: forall m. (DsMonad m, MonadReaders TypeGraph m) => TGVSimple -> m (Set TGVSimple)
reachableFromSimple v = do
(g, vf, kf) <- view' gsimple
case kf v of
Nothing -> return Set.empty
Just v' -> return $ Set.map (\(_, key, _) -> key) . Set.map vf $ Set.fromList $ reachable (transposeG g) v'
goalReachableFull :: (Functor m, DsMonad m, MonadReaders TypeGraph m) => TGV -> TGV -> m Bool
goalReachableFull gkey key0 = isReachable gkey key0 <$> view' graph
goalReachableSimple :: (Functor m, DsMonad m, MonadReaders TypeGraph m) => TGVSimple -> TGVSimple -> m Bool
goalReachableSimple gkey key0 = isReachable gkey key0 <$> view' gsimple
goalReachableSimple' :: (Functor m, DsMonad m, MonadReaders TypeGraph m) => TGV -> TGV -> m Bool
goalReachableSimple' gkey key0 = goalReachableSimple (view vsimple gkey) (view vsimple key0)
isReachable :: TypeGraphVertex key => key -> key -> (Graph, Vertex -> ((), key, [key]), key -> Maybe Vertex) -> Bool
isReachable gkey key0 (g, _vf, kf) = path g (fromJust $ kf key0) (fromJust $ kf gkey)
typeGraphVertex :: ( MonadReaders TypeInfo m, MonadStates ExpandMap m, DsMonad m) => Type -> m TGV
typeGraphVertex typ = do
typ' <- expandType typ
askPoly >>= \(ti :: TypeInfo) -> MTL.runReaderT (typeVertex' typ') ti
typeGraphVertexOfField :: ( MonadReaders TypeInfo m, MonadStates ExpandMap m, DsMonad m) =>
(Name, Name, Either Int Name) -> Type -> m TGV
typeGraphVertexOfField fld typ = do
typ' <- expandType typ
askPoly >>= \(ti :: TypeInfo) -> MTL.runReaderT (fieldVertex fld typ') ti
data VertexStatus typ
= Vertex
| Sink
| Divert typ
| Extra typ
deriving Show
instance Default (VertexStatus typ) where
def = Vertex
adjacent :: forall m. ( MonadReaders TypeInfo m, DsMonad m, MonadStates ExpandMap m) => TGV -> m (Set TGV)
adjacent typ =
case view (vsimple . etype) typ of
E (ForallT _ _ typ') -> typeGraphVertex typ' >>= adjacent
E (AppT c e) ->
typeGraphVertex c >>= \c' ->
typeGraphVertex e >>= \e' ->
return $ Set.fromList [c', e']
E (ConT name) -> do
info <- qReify name
case info of
TyConI dec -> doDec dec
_ -> return mempty
_typ -> return $ mempty
where
doDec :: Dec -> m (Set TGV)
doDec dec@(NewtypeD _ tname _ con _) = doCon tname dec con
doDec dec@(DataD _ tname _ cns _) = Set.unions <$> Traversable.mapM (doCon tname dec) cns
doDec (TySynD _tname _tvars typ') = singleton <$> typeGraphVertex typ'
doDec _ = return mempty
doCon :: Name -> Dec -> Con -> m (Set TGV)
doCon tname dec (ForallC _ _ con) = doCon tname dec con
doCon tname dec (NormalC cname fields) = Set.unions <$> Traversable.mapM (doField tname dec cname) (zip (List.map Left ([1..] :: [Int])) (List.map snd fields))
doCon tname dec (RecC cname fields) = Set.unions <$> Traversable.mapM (doField tname dec cname) (List.map (\ (fname, _, typ') -> (Right fname, typ')) fields)
doCon tname dec (InfixC (_, lhs) cname (_, rhs)) = Set.unions <$> Traversable.mapM (doField tname dec cname) [(Left 1, lhs), (Left 2, rhs)]
doField :: Name -> Dec -> Name -> (Either Int Name, Type) -> m (Set TGV)
doField tname _dec cname (fld, ftype) = Set.singleton <$> typeGraphVertexOfField (tname, cname, fld) ftype