th-context-0.24: Data/Logic/ATP/TH.hs
-- | ATP instances for the template haskell type 'Type', and the
-- conjunction of such types, @[Type]@. In these instances, almost
-- every role is played by 'Type'. It might a case where the tagged
-- package could be used to advantage. A list represents conjunction,
-- but there is no disjunction operation, nor any derived from it like
-- implication or equivalence.
{-# LANGUAGE CPP, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, TypeFamilies, UndecidableInstances #-}
module Data.Logic.ATP.TH
( unfoldApply
, expandBindings
) where
import Control.Monad.State (modify)
import Data.Generics (everywhere, mkT)
import Data.List (intersperse)
import Data.Logic.ATP (IsAtom, IsVariable(..), IsFunction, IsPredicate, HasEquate(..))
import Data.Logic.ATP.Apply (HasApply(PredOf, TermOf, applyPredicate, foldApply', overterms, onterms))
import Data.Logic.ATP.Formulas (IsFormula(..))
import Data.Logic.ATP.Lit (IsLiteral(..), JustLiteral)
import Data.Logic.ATP.Pretty (hcat, HasFixity(..), Pretty(pPrint), text)
import Data.Logic.ATP.Prop (IsPropositional(..))
import Data.Logic.ATP.Term (IsTerm(..))
import Data.Logic.ATP.Unif (Unify(UTermOf, unify'), unify_literals)
import Data.Map as Map (insertWithKey, lookup, Map)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Data.String (IsString(fromString))
import Language.Haskell.TH
import Language.Haskell.TH.PprLib (to_HPJ_Doc)
import Language.Haskell.TH.Expand (pprint1)
newtype Context = Context [Type] deriving (Eq, Ord, Show)
-- | Helper function to interpret a type application:
-- @unfoldApply (AppT (AppT (AppT (VarT (mkName "a")) StarT) ListT) ArrowT) -> (VarT (mkName "a"), [StarT, ListT, ArrowT])@
-- The inverse is @uncurry . foldl AppT@.
unfoldApply :: Type -> [Type] -> (Type, [Type])
unfoldApply (AppT t1 t2) ts = unfoldApply t1 (t2 : ts)
unfoldApply t ts = (t, ts)
instance HasFixity Type where
precedence _ = undefined
associativity _ = undefined
instance Pretty Type where
pPrint = to_HPJ_Doc . ppr
instance Pretty Context where
pPrint (Context ts) = text "(" <> hcat (intersperse (text ", ") (map pPrint ts)) <> text ")"
instance IsAtom Type
instance IsAtom Context
instance IsString Type where
fromString = VarT . mkName
instance IsString Context where
fromString = Context . (: []) . fromString
instance IsVariable Type where
variant _v _vs = error "variant" -- Maybe we should use newName here? That means using the Q monad everywhere.
prefix p (VarT name) = VarT (mkName (p ++ nameBase name))
prefix _p typ = error $ "IsVariable " ++ pprint typ
instance IsFunction Type
-- For type Type, the domain elements are concrete types, while
-- predicates are either EqualityT or class names applied to a
-- suitable number of class type parameters.
instance IsPredicate Type
instance IsTerm Type where
type (TVarOf Type) = Type
type (FunOf Type) = Type
vt = id
fApp _fn _ts = error "fApp"
foldTerm vf _af x@(VarT _) = vf x
foldTerm _vf af x@(ConT _) = af x []
foldTerm _vf af x = af x []
-- foldTerm _vf _af t = error $ "foldTerm: " ++ show t
instance HasApply Type where
type (PredOf Type) = Type
type (TermOf Type) = Type
applyPredicate p ts = foldl AppT p ts
foldApply' _atomf applyf x = uncurry applyf (unfoldApply x []) -- Not yet clear what values comprise the atom type
overterms _f _r0 _x = error "overterms"
onterms _f _x = error "onterms"
-- EqualityT is the only predicate I am aware of.
instance HasEquate Type where
equate a b = AppT (AppT EqualityT a) b
foldEquate eq _ap (AppT (AppT EqualityT a) b) = eq a b
foldEquate _eq ap t = uncurry ap (unfoldApply t [])
instance IsFormula Type where
type (AtomOf Type) = Type
true = error "true"
false = error "false"
asBool = error "asBool"
atomic = id
overatoms _f _fm _r0 = error "overatoms"
onatoms _f _fm = error "onatoms"
instance IsLiteral Type where
naiveNegate x = error $ "naiveNegate " ++ show x
foldNegation _f _ne x = error $ "foldNegation " ++ show x
foldLiteral' _ho _ne _tf at x = at x -- I don't yet know what types are true, false, or negation. They may not exist.
-- foldLiteral' _ho _ne _tf _at x = error $ "foldLiteral' " ++ show x
instance JustLiteral Type
instance HasFixity Context where
precedence _ = undefined
associativity _ = undefined
instance IsFormula Context where
type (AtomOf Context) = Type
true = error "true"
false = error "false"
asBool = error "asBool"
atomic = Context . (: [])
overatoms _f _fm _r0 = error "overatoms"
onatoms _f _fm = error "onatoms"
-- A list of types are considered to be AND-ed, as in the 'Cxt' type.
instance IsLiteral Context where
naiveNegate (Context [x]) = Context [naiveNegate x]
naiveNegate _lits = error "Invalid Literal"
foldNegation _f _ne x = error $ "foldNegation " ++ show x
foldLiteral' _ho _ne _tf at (Context [x]) = at x -- I don't yet know what types are true, false, or negation. They may not exist.
foldLiteral' _ho _ne _tf _at x = error $ "foldLiteral' " ++ show x
instance IsPropositional Context where
Context a .&. Context b = Context (a <> b)
(.|.) = error "IsPropositional Type: Disjunction not supported"
(.<=>.) = error "IsPropositional Type: IFF not supported"
(.=>.) = error "IsPropositional Type: Imp not supported"
foldPropositional' = error "foldPropositional'"
foldCombination = error "foldCombination"
instance Monad m => Unify m Type where
type UTermOf Type = TermOf Type
unify' (AppT (AppT EqualityT a@(VarT _)) b) = modify (bind a b)
unify' (AppT (AppT EqualityT a) b@(VarT _)) = modify (bind b a)
unify' (AppT (AppT EqualityT (AppT a b)) (AppT c d)) =
-- I'm told this is incorrect in the presence of type functions
unify' (AppT (AppT EqualityT a) c) >> unify' (AppT (AppT EqualityT b) d)
unify' (AppT (AppT EqualityT a) b) | a == b = return ()
unify' (AppT (AppT EqualityT a) b) = fail $ "Cannot unify: (" ++ pprint1 a ++ ", " ++ pprint1 b ++ ")"
unify' _ = return ()
instance Monad m => Unify m [Type] where
type UTermOf [Type] = TermOf Type
unify' = mapM_ unify'
-- | Create a new variable binding, making sure all bound variables in
-- are expanded in the resulting map.
bind :: Pred -> Pred -> Map Pred Pred -> Map Pred Pred
bind v@(VarT _) a mp =
-- First, expand all occurrences of the new variable in existing bindings
let mp' = everywhere (mkT (expandBinding v a)) mp in
-- Next, expand all bound variables in the new binding
let a' = everywhere (mkT (expandBindings mp')) a in
-- Does this introduce any recursive bindings?
let a'' = everywhere (mkT (expandBinding v (error $ "Recursive binding of " ++ show v))) a' in
-- If the value is already bound, make sure the binding is identical
Map.insertWithKey (\v' a1 a2 ->
if a1 == a2
then a1
else error ("Conflicting definitions of " ++ show v' ++ ":\n " ++ show a1 ++ "\n " ++ show a2)) v a'' mp'
expandBindings :: Map Pred Pred -> Pred -> Pred
expandBindings mp x@(VarT _) = fromMaybe x (Map.lookup x mp)
expandBindings _ x = x
expandBinding :: Pred -> Pred -> Pred -> Pred
expandBinding v a x = if x == v then a else x