quickspec-2.2.1: src/QuickSpec/Internal/Pruning/Conditionals.hs
-- Encode conditionals during pruning.
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, FlexibleContexts, ScopedTypeVariables, UndecidableInstances, DeriveGeneric #-}
module QuickSpec.Internal.Pruning.Conditionals where
import QuickSpec.Internal.Pruning
import QuickSpec.Internal.Pruning.Background(Background(..))
import QuickSpec.Internal.Testing
import QuickSpec.Internal.Term
import QuickSpec.Internal.Type
import QuickSpec.Internal.Prop hiding (mapFun)
import QuickSpec.Internal.Terminal
import QuickSpec.Internal.Utils
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import GHC.Generics
import Data.Hashable
import Data.Hashable.Generic
data Conditionals fun =
Func fun
| Guard Type (UnconditionalTerm fun) (UnconditionalTerm fun) (UnconditionalTerm fun) (UnconditionalTerm fun) [Var]
deriving (Eq, Ord, Show, Typeable, Generic)
instance Hashable fun => Hashable (Conditionals fun) where
hashWithSalt = genericHashWithSalt
instance Arity fun => Arity (Conditionals fun) where
arity (Func f) = arity f
arity (Guard _ _ _ _ _ vs) = length vs + 1
instance Sized fun => Sized (Conditionals fun) where
size (Func f) = size f
size Guard{} = 0
instance Sized fun => FuncSized (Conditionals fun) where
-- Note: since there is no FuncSized instance for PartiallyApplied
-- we just assume that Func f is adding the size of its arguments
sizeApp (Func f) ts = size f + sum ts
sizeApp Guard{} ts = penalty + maximum ts
where
penalty = 3
instance Pretty fun => Pretty (Conditionals fun) where
pPrint (Func f) = pPrint f
pPrint Guard{} = text "guard"
instance PrettyTerm fun => PrettyTerm (Conditionals fun) where
termStyle (Func f) = termStyle f
termStyle Guard{} = uncurried
instance Typed fun => Typed (Conditionals fun) where
typ (Func f) = typ f
typ (Guard ty t _ _ _ vs) = arrowType (typ t:map typ vs) ty
typeSubst_ sub (Func f) = Func (typeSubst_ sub f)
typeSubst_ sub (Guard ty t u v w vs) = Guard (typeSubst_ sub ty) (typeSubst_ sub t) (typeSubst_ sub u) (typeSubst_ sub v) (typeSubst_ sub w) (typeSubst_ sub vs)
instance EqualsBonus (Conditionals fun) where
type ConditionalTerm fun = Term fun
type UnconditionalTerm fun = Term (Conditionals fun)
newtype Pruner fun pruner a =
Pruner { run :: pruner a }
deriving (Functor, Applicative, Monad, MonadIO, MonadTester testcase term, MonadTerminal)
instance MonadTrans (Pruner fun) where
lift = Pruner
instance (PrettyTerm fun, Typed fun, MonadPruner (UnconditionalTerm fun) norm pruner) => MonadPruner (ConditionalTerm fun) norm (Pruner fun pruner) where
normaliser =
Pruner $ do
norm <- normaliser :: pruner (UnconditionalTerm fun -> norm)
return $ \t ->
norm . mapFun Func $ t
add prop = and <$> lift (mapM add (conditionalise' (canonicalise prop)))
decodeNormalForm hole t =
Pruner $ do
t <- decodeNormalForm (fmap (fmap Func) . hole) t
let elimIfEq (Func f) = Just f
elimIfEq Guard{} = Nothing
return $ t >>= mapFunM elimIfEq
instance (Typed fun, Arity fun, Background fun) => Background (Conditionals fun) where
background (Func f) = concatMap conditionalise' (background f)
background Guard{} = []
conditionalise :: Typed fun => Prop (UnconditionalTerm fun) -> [Prop (UnconditionalTerm fun)]
conditionalise prop@([] :=>: _) = [prop]
conditionalise ((t :=: u):lhs :=>: v :=: w) =
([] :=>: guarded t v):conditionalise (lhs :=>: guarded u w)
where
guarded x y = Fun (Guard ty t u v w vs) :@: (x:map Var vs) :=: y
vs = usort (concatMap vars [t, u, v, w])
ty = typ t
conditionalise' :: Typed fun => Prop (ConditionalTerm fun) -> [Prop (UnconditionalTerm fun)]
conditionalise' = conditionalise . mapTerm (mapFun Func)