packages feed

quickspec-2.2: src/QuickSpec/Internal/Pruning.hs

-- A type of pruners.
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE FunctionalDependencies, GeneralizedNewtypeDeriving, FlexibleInstances, UndecidableInstances, DefaultSignatures, GADTs, TypeOperators, DeriveFunctor, DeriveTraversable #-}
module QuickSpec.Internal.Pruning where

import QuickSpec.Internal.Prop
import QuickSpec.Internal.Testing
import QuickSpec.Internal.Type(Type)
import Twee.Pretty
import Control.Monad.Trans.Class
import Control.Monad.IO.Class
import Control.Monad.Trans.State.Strict
import Control.Monad.Trans.Reader
import Data.Maybe

data Theorem norm =
  Theorem {
    prop :: Prop norm,
    axiomsUsed :: [(Prop norm, [Prop norm])] }
  deriving (Functor, Foldable, Traversable)

instance Pretty norm => Pretty (Theorem norm) where
  pPrint thm =
    (text "prop =" <+> pPrint (prop thm)) $$
    (text "axioms used =" <+> pPrint (axiomsUsed thm))

class Monad m => MonadPruner term norm m | m -> term norm where
  normaliser :: m (term -> norm)
  add :: Prop term -> m Bool
  decodeNormalForm :: (Type -> Maybe term) -> norm -> m (Maybe term)
  normTheorems :: m [Theorem norm]

  default normaliser :: (MonadTrans t, MonadPruner term norm m', m ~ t m') => m (term -> norm)
  normaliser = lift normaliser

  default add :: (MonadTrans t, MonadPruner term norm m', m ~ t m') => Prop term -> m Bool
  add = lift . add

  default normTheorems :: (MonadTrans t, MonadPruner term' norm m', m ~ t m') => m [Theorem norm]
  normTheorems = lift normTheorems

  default decodeNormalForm :: (MonadTrans t, MonadPruner term norm m', m ~ t m') => (Type -> Maybe term) -> norm -> m (Maybe term)
  decodeNormalForm hole t = lift (decodeNormalForm hole t)

decodeTheorem :: MonadPruner term norm m => (Type -> Maybe term) -> Theorem norm -> m (Maybe (Theorem term))
decodeTheorem hole thm = elimMaybeThm <$> mapM (decodeNormalForm hole) thm
  where
    elimMaybeThm (Theorem prop axs) =
      case sequence prop of
        Nothing -> Nothing
        Just prop -> Just (Theorem prop (mapMaybe elimMaybeAx axs))
    elimMaybeAx (ax, insts) =
      case sequence ax of
        Nothing -> Nothing
        Just ax -> Just (ax, mapMaybe elimMaybeInst insts)
    elimMaybeInst = sequence

theorems :: MonadPruner term norm m => (Type -> Maybe term) -> m [Theorem term]
theorems hole = do
  thms <- normTheorems
  catMaybes <$> mapM (decodeTheorem hole) thms

instance MonadPruner term norm m => MonadPruner term norm (StateT s m)
instance MonadPruner term norm m => MonadPruner term norm (ReaderT r m)

normalise :: MonadPruner term norm m => term -> m norm
normalise t = do
  norm <- normaliser
  return (norm t)

newtype ReadOnlyPruner m a = ReadOnlyPruner { withReadOnlyPruner :: m a }
  deriving (Functor, Applicative, Monad, MonadIO, MonadTester testcase term)

instance MonadTrans ReadOnlyPruner where
  lift = ReadOnlyPruner

instance MonadPruner term norm m => MonadPruner term norm (ReadOnlyPruner m) where
  normaliser = ReadOnlyPruner normaliser
  add _ = return True

newtype WatchPruner term m a = WatchPruner (StateT [Prop term] m a)
  deriving (Functor, Applicative, Monad, MonadTrans, MonadIO, MonadTester testcase term)

instance MonadPruner term norm m => MonadPruner term norm (WatchPruner term m) where
  normaliser = lift normaliser
  add prop = do
    res <- lift (add prop)
    WatchPruner (modify (prop:))
    return res

watchPruner :: Monad m => WatchPruner term m a -> m (a, [Prop term])
watchPruner (WatchPruner mx) = do
  (x, props) <- runStateT mx []
  return (x, reverse props)