{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE GeneralisedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
module Control.Monad.MoriarT
( MoriarT (..)
, runAll
, runOne
, solve
, unsafeRead
) where
import Control.Applicative (Alternative (..))
import Control.Monad (MonadPlus, guard)
import Control.Monad.Cell.Class (MonadCell (..))
import qualified Control.Monad.Cell.Class as Cell
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Logic (MonadLogic, LogicT (..))
import qualified Control.Monad.Logic as LogicT
import Control.Monad.Primitive (PrimMonad (..))
import Control.Monad.Reader.Class (MonadReader (..))
import qualified Control.Monad.Reader.Class as Reader
import Control.Monad.State.Class (MonadState (..))
import qualified Control.Monad.State.Class as State
import Control.Monad.Trans.Class (MonadTrans (..))
import Control.Monad.Trans.Reader (ReaderT (..))
import Control.Monad.Trans.State (StateT (..))
import qualified Control.Monad.Trans.State as StateT
import qualified Data.CDCL as CDCL
import Data.Foldable (asum)
import Data.Function ((&))
import Data.Functor ((<&>))
import Data.Input.Config (Config (..))
import Data.JoinSemilattice.Class.Boolean (BooleanR (..))
import Data.JoinSemilattice.Class.Eq (EqR (..))
import Data.JoinSemilattice.Class.Merge (Merge (..), Result (..))
import Data.Kind (Type)
import Data.Maybe (listToMaybe)
import Data.Monoid (Ap (..))
import Data.Primitive.MutVar (MutVar)
import qualified Data.Primitive.MutVar as MutVar
import Data.Propagator (Prop)
import qualified Data.Propagator as Prop
import Type.Reflection (Typeable)
newtype MoriarT (m :: Type -> Type) (x :: Type)
= MoriarT
{ unMoriarT :: ReaderT CDCL.Rule (LogicT (StateT CDCL.Group m)) x
}
deriving newtype
( Functor
, Applicative
, Alternative
, Monad
, MonadIO
, MonadLogic
, MonadPlus
, MonadReader CDCL.Rule
, MonadState CDCL.Group
)
deriving (Semigroup, Monoid)
via (Ap (MoriarT m) x)
instance MonadTrans MoriarT where
lift = MoriarT . lift . lift . lift
instance PrimMonad m => PrimMonad (MoriarT m) where
type PrimState (MoriarT m) = PrimState m
primitive = lift . primitive
instance PrimMonad m => MonadCell (MoriarT m) where
newtype Cell (MoriarT m) (content :: Type)
= Cell (MutVar (PrimState m) (CDCL.Rule, content, MoriarT m ()))
discard = do
context <- Reader.ask
State.modify (CDCL.resolve context)
empty
fill content = do
context <- Reader.ask
mutVar <- MutVar.newMutVar (context, content, mempty)
pure (Cell mutVar)
watch cell@(Cell mutVar) propagator = do
let next = with cell propagator
before@(provenance, content, callbacks)
<- MutVar.readMutVar mutVar
MutVar.writeMutVar mutVar (provenance, content, callbacks *> next) *> next
<|> MutVar.writeMutVar mutVar before *> empty
with (Cell mutVar) callback = do
(provenance, content, _) <- MutVar.readMutVar mutVar
Reader.local (<> provenance) (callback content)
write (Cell mutVar) news = do
context <- Reader.ask
nogoods <- State.get
before@(provenance, content, callbacks)
<- MutVar.readMutVar mutVar
let provenance' = context <> provenance
content' = content <<- news
guard (not (nogoods `CDCL.implies` provenance'))
case content' of
Changed update -> do
MutVar.writeMutVar mutVar (provenance', update, callbacks) *> callbacks
<|> MutVar.writeMutVar mutVar before *> empty
Failure -> Reader.local (<> context) discard
Unchanged -> pure ()
unsafeRead :: PrimMonad m => Cell (MoriarT m) x -> MoriarT m x
unsafeRead (Cell mutVar) = do
(_, content, _) <- MutVar.readMutVar mutVar
pure content
runAll :: Monad m => MoriarT m x -> m [ x ]
runAll
= flip StateT.evalStateT mempty
. LogicT.observeAllT
. flip runReaderT mempty
. unMoriarT
runOne :: Monad m => MoriarT m x -> m (Maybe x)
runOne
= fmap listToMaybe
. flip StateT.evalStateT mempty
. LogicT.observeManyT 1
. flip runReaderT mempty
. unMoriarT
solve :: (PrimMonad m, EqR x b, Merge x, Typeable x) => Config (MoriarT m) x -> (forall f. MonadCell f => [ Prop f x ] -> Prop f b) -> MoriarT m [ x ]
solve Config{..} predicate = do
inputs <- traverse Cell.fill initial
output <- Prop.down (predicate (map Prop.up inputs))
Cell.write output trueR
_ <- zip [0 ..] inputs & traverse \(major, cell) -> do
current <- unsafeRead cell
refinements <- refine current
input <- asum $ CDCL.index major refinements <&> \(rule, content) ->
fmap Cell (MutVar.newMutVar (rule, content, mempty))
Cell.unify cell input
traverse unsafeRead inputs