{-# LANGUAGE DataKinds, UndecidableInstances, FlexibleContexts #-}
{-# LANGUAGE TypeFamilies, TypeOperators #-}
module Language.Souffle.Class
( Program(..)
, Fact(..)
, Marshal.Marshal(..)
, Direction(..)
, ContainsInputFact
, ContainsOutputFact
, ContainsFact
, MonadSouffle(..)
, MonadSouffleFileIO(..)
) where
import Prelude hiding ( init )
import Control.Monad.Except
import Control.Monad.RWS.Strict
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Writer
import Data.Proxy
import Data.Kind
import Data.Word
import qualified Language.Souffle.Marshal as Marshal
import Type.Errors.Pretty
type family ContainsInputFact prog fact :: Constraint where
ContainsInputFact prog fact = (ContainsFact prog fact, IsInput fact (FactDirection fact))
type family ContainsOutputFact prog fact :: Constraint where
ContainsOutputFact prog fact = (ContainsFact prog fact, IsOutput fact (FactDirection fact))
type family IsInput (fact :: Type) (dir :: Direction) :: Constraint where
IsInput _ 'Input = ()
IsInput _ 'InputOutput = ()
IsInput fact dir = TypeError
( "You tried to use an " <> FormatDirection dir <> " fact of type " <> fact <> " as an input."
% "Possible solution: change the FactDirection of " <> fact
<> " to either 'Input' or 'InputOutput'."
)
type family IsOutput (fact :: Type) (dir :: Direction) :: Constraint where
IsOutput _ 'Output = ()
IsOutput _ 'InputOutput = ()
IsOutput fact dir = TypeError
( "You tried to use an " <> FormatDirection dir <> " fact of type " <> fact <> " as an output."
% "Possible solution: change the FactDirection of " <> fact
<> " to either 'Output' or 'InputOutput'."
)
type family FormatDirection (dir :: Direction) where
FormatDirection 'Output = "output"
FormatDirection 'Input = "input"
FormatDirection 'Internal = "internal"
type family ContainsFact prog fact :: Constraint where
ContainsFact prog fact =
CheckContains prog (ProgramFacts prog) fact
type family CheckContains prog facts fact :: Constraint where
CheckContains prog '[] fact =
TypeError ("You tried to perform an action with a fact of type '" <> fact
<> "' for program '" <> prog <> "'."
% "The program contains the following facts: " <> ProgramFacts prog <> "."
% "It does not contain fact: " <> fact <> "."
% "You can fix this error by adding the type '" <> fact
<> "' to the ProgramFacts type in the Program instance for " <> prog <> ".")
CheckContains _ (a ': _) a = ()
CheckContains prog (_ ': as) b = CheckContains prog as b
class Program a where
type ProgramFacts a :: [Type]
programName :: a -> String
class Marshal.Marshal a => Fact a where
type FactDirection a :: Direction
factName :: Proxy a -> String
data Direction
= Input
| Output
| InputOutput
| Internal
class Monad m => MonadSouffle m where
type Handler m :: Type -> Type
type CollectFacts m (c :: Type -> Type) :: Constraint
run :: Handler m prog -> m ()
setNumThreads :: Handler m prog -> Word64 -> m ()
getNumThreads :: Handler m prog -> m Word64
getFacts :: (Fact a, ContainsOutputFact prog a, CollectFacts m c)
=> Handler m prog -> m (c a)
findFact :: (Fact a, ContainsOutputFact prog a, Eq a)
=> Handler m prog -> a -> m (Maybe a)
addFact :: (Fact a, ContainsInputFact prog a)
=> Handler m prog -> a -> m ()
addFacts :: (Foldable t, Fact a, ContainsInputFact prog a)
=> Handler m prog -> t a -> m ()
instance MonadSouffle m => MonadSouffle (ReaderT r m) where
type Handler (ReaderT r m) = Handler m
type CollectFacts (ReaderT r m) c = CollectFacts m c
run = lift . run
{-# INLINABLE run #-}
setNumThreads prog = lift . setNumThreads prog
{-# INLINABLE setNumThreads #-}
getNumThreads = lift . getNumThreads
{-# INLINABLE getNumThreads #-}
getFacts = lift . getFacts
{-# INLINABLE getFacts #-}
findFact prog = lift . findFact prog
{-# INLINABLE findFact #-}
addFact fact = lift . addFact fact
{-# INLINABLE addFact #-}
addFacts facts = lift . addFacts facts
{-# INLINABLE addFacts #-}
instance (Monoid w, MonadSouffle m) => MonadSouffle (WriterT w m) where
type Handler (WriterT w m) = Handler m
type CollectFacts (WriterT w m) c = CollectFacts m c
run = lift . run
{-# INLINABLE run #-}
setNumThreads prog = lift . setNumThreads prog
{-# INLINABLE setNumThreads #-}
getNumThreads = lift . getNumThreads
{-# INLINABLE getNumThreads #-}
getFacts = lift . getFacts
{-# INLINABLE getFacts #-}
findFact prog = lift . findFact prog
{-# INLINABLE findFact #-}
addFact fact = lift . addFact fact
{-# INLINABLE addFact #-}
addFacts facts = lift . addFacts facts
{-# INLINABLE addFacts #-}
instance MonadSouffle m => MonadSouffle (StateT s m) where
type Handler (StateT s m) = Handler m
type CollectFacts (StateT s m) c = CollectFacts m c
run = lift . run
{-# INLINABLE run #-}
setNumThreads prog = lift . setNumThreads prog
{-# INLINABLE setNumThreads #-}
getNumThreads = lift . getNumThreads
{-# INLINABLE getNumThreads #-}
getFacts = lift . getFacts
{-# INLINABLE getFacts #-}
findFact prog = lift . findFact prog
{-# INLINABLE findFact #-}
addFact fact = lift . addFact fact
{-# INLINABLE addFact #-}
addFacts facts = lift . addFacts facts
{-# INLINABLE addFacts #-}
instance (MonadSouffle m, Monoid w) => MonadSouffle (RWST r w s m) where
type Handler (RWST r w s m) = Handler m
type CollectFacts (RWST r w s m) c = CollectFacts m c
run = lift . run
{-# INLINABLE run #-}
setNumThreads prog = lift . setNumThreads prog
{-# INLINABLE setNumThreads #-}
getNumThreads = lift . getNumThreads
{-# INLINABLE getNumThreads #-}
getFacts = lift . getFacts
{-# INLINABLE getFacts #-}
findFact prog = lift . findFact prog
{-# INLINABLE findFact #-}
addFact fact = lift . addFact fact
{-# INLINABLE addFact #-}
addFacts facts = lift . addFacts facts
{-# INLINABLE addFacts #-}
instance MonadSouffle m => MonadSouffle (ExceptT e m) where
type Handler (ExceptT e m) = Handler m
type CollectFacts (ExceptT e m) c = CollectFacts m c
run = lift . run
{-# INLINABLE run #-}
setNumThreads prog = lift . setNumThreads prog
{-# INLINABLE setNumThreads #-}
getNumThreads = lift . getNumThreads
{-# INLINABLE getNumThreads #-}
getFacts = lift . getFacts
{-# INLINABLE getFacts #-}
findFact prog = lift . findFact prog
{-# INLINABLE findFact #-}
addFact fact = lift . addFact fact
{-# INLINABLE addFact #-}
addFacts facts = lift . addFacts facts
{-# INLINABLE addFacts #-}
class MonadSouffle m => MonadSouffleFileIO m where
loadFiles :: Handler m prog -> FilePath -> m ()
writeFiles :: Handler m prog -> FilePath -> m ()
instance MonadSouffleFileIO m => MonadSouffleFileIO (ReaderT r m) where
loadFiles prog = lift . loadFiles prog
{-# INLINABLE loadFiles #-}
writeFiles prog = lift . writeFiles prog
{-# INLINABLE writeFiles #-}
instance (Monoid w, MonadSouffleFileIO m) => MonadSouffleFileIO (WriterT w m) where
loadFiles prog = lift . loadFiles prog
{-# INLINABLE loadFiles #-}
writeFiles prog = lift . writeFiles prog
{-# INLINABLE writeFiles #-}
instance MonadSouffleFileIO m => MonadSouffleFileIO (StateT s m) where
loadFiles prog = lift . loadFiles prog
{-# INLINABLE loadFiles #-}
writeFiles prog = lift . writeFiles prog
{-# INLINABLE writeFiles #-}
instance (MonadSouffleFileIO m, Monoid w) => MonadSouffleFileIO (RWST r w s m) where
loadFiles prog = lift . loadFiles prog
{-# INLINABLE loadFiles #-}
writeFiles prog = lift . writeFiles prog
{-# INLINABLE writeFiles #-}
instance MonadSouffleFileIO m => MonadSouffleFileIO (ExceptT s m) where
loadFiles prog = lift . loadFiles prog
{-# INLINABLE loadFiles #-}
writeFiles prog = lift . writeFiles prog
{-# INLINABLE writeFiles #-}