{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE RecordWildCards, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, FlexibleContexts, ScopedTypeVariables, UndecidableInstances #-}
module QuickSpec.Pruning.Types where
import QuickSpec.Pruning
import qualified QuickSpec.Pruning.Background as Background
import QuickSpec.Pruning.Background(Background)
import QuickSpec.Testing
import QuickSpec.Term
import QuickSpec.Type
import QuickSpec.Prop
import QuickSpec.Terminal
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import qualified Twee.Base as Twee
data Tagged fun =
Func fun
| Tag Type
deriving (Eq, Ord, Show, Typeable)
instance Arity fun => Arity (Tagged fun) where
arity (Func f) = arity f
arity (Tag _) = 1
instance Sized fun => Sized (Tagged fun) where
size (Func f) = size f
size (Tag _) = 0
instance Sized fun => Twee.Sized (Tagged fun) where
size f = size f `max` 1
instance Pretty fun => Pretty (Tagged fun) where
pPrint (Func f) = pPrint f
pPrint (Tag ty) = text "tag[" <#> pPrint ty <#> text "]"
instance PrettyTerm fun => PrettyTerm (Tagged fun) where
termStyle (Func f) = termStyle f
termStyle (Tag _) = uncurried
instance EqualsBonus (Tagged fun) where
type TypedTerm fun = Term fun
type UntypedTerm fun = Term (Tagged 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 (UntypedTerm fun) (UntypedTerm fun) pruner) => MonadPruner (TypedTerm fun) (TypedTerm fun) (Pruner fun pruner) where
normaliser =
Pruner $ do
norm <- normaliser :: pruner (UntypedTerm fun -> UntypedTerm fun)
return $ \t ->
decode . norm . encode $ t
add prop = lift (add (encode <$> canonicalise prop))
instance (Typed fun, Arity fun) => Background (Tagged fun) where
background = typingAxioms
typingAxioms :: (Typed fun, Arity fun) =>
Tagged fun -> [Prop (UntypedTerm fun)]
typingAxioms (Tag ty) =
[tag ty (tag ty x) === tag ty x]
where
x = Var (V ty 0)
typingAxioms (Func func) =
[tag res t === t] ++
[tagArg i ty === t | (i, ty) <- zip [0..] args]
where
f = Func func
xs = take n (map (Var . V typeVar) [0..])
ty = typ func
n = arity func
args = take n (typeArgs ty)
res = typeDrop n ty
t = App f xs
tagArg i ty =
App f $
take i xs ++
[tag ty (xs !! i)] ++
drop (i+1) xs
tag :: Type -> UntypedTerm fun -> UntypedTerm fun
tag ty t = App (Tag ty) [t]
encode :: Typed fun => TypedTerm fun -> UntypedTerm fun
encode (Var x) = tag (typ x) (Var x)
encode (App f ts) =
tag (typeDrop (length ts) (typ f)) (App (Func f) (map encode ts))
decode :: Typed fun => UntypedTerm fun -> TypedTerm fun
decode = dec Nothing
where
dec _ (App (Tag ty) [t]) =
dec (Just ty) t
dec _ (App Tag{} _) =
error "Tag function applied with wrong arity"
dec (Just ty) (Var (V _ x)) =
Var (V ty x)
dec Nothing (Var _) =
error "Naked variable in type-encoded term"
dec _ (App (Func f) ts) =
App f $
zipWith dec
(map Just (typeArgs (typ f)))
ts