module HOL.TypeSubst
where
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe)
import Data.Set (Set)
import qualified Data.Set as Set
import HOL.Data
import qualified HOL.Type as Type
data TypeSubst = TypeSubst (Map TypeVar Type) (Map Type (Maybe Type))
mk :: Map TypeVar Type -> TypeSubst
mk m =
TypeSubst (Map.filterWithKey norm m) Map.empty
where
norm v ty = not $ Type.eqVar v ty
dest :: TypeSubst -> Map TypeVar Type
dest (TypeSubst m _) = m
fromList :: [(TypeVar,Type)] -> TypeSubst
fromList = mk . Map.fromList
empty :: TypeSubst
empty = fromList []
singleton :: TypeVar -> Type -> TypeSubst
singleton v ty = fromList [(v,ty)]
null :: TypeSubst -> Bool
null = Map.null . dest
instance Eq TypeSubst where
sub1 == sub2 = dest sub1 == dest sub2
varSubst :: TypeVar -> TypeSubst -> Maybe Type
varSubst v (TypeSubst m _) = Map.lookup v m
dataSubst :: TypeData -> TypeSubst -> (Maybe Type, TypeSubst)
dataSubst (VarType v) s = (varSubst v s, s)
dataSubst (OpType t tys) s =
(fmap (Type.mkOp t) tys', s')
where
(tys',s') = basicSubst tys s
class CanSubst a where
basicSubst :: a -> TypeSubst -> (Maybe a, TypeSubst)
sharingSubst :: a -> TypeSubst -> (Maybe a, TypeSubst)
sharingSubst x s =
if HOL.TypeSubst.null s then (Nothing,s) else basicSubst x s
subst :: TypeSubst -> a -> Maybe a
subst s x = fst $ sharingSubst x s
trySharingSubst :: a -> TypeSubst -> (a,TypeSubst)
trySharingSubst x s = (fromMaybe x x', s') where (x',s') = sharingSubst x s
trySubst :: TypeSubst -> a -> a
trySubst s x = fromMaybe x (subst s x)
instance CanSubst a => CanSubst [a] where
basicSubst [] s = (Nothing,s)
basicSubst (h : t) s =
(l',s'')
where
(h',s') = basicSubst h s
(t',s'') = basicSubst t s'
l' = case h' of
Nothing -> fmap ((:) h) t'
Just x -> Just (x : fromMaybe t t')
instance (Ord a, CanSubst a) => CanSubst (Set a) where
basicSubst xs s =
(xs',s')
where
xl = Set.toList xs
(xl',s') = basicSubst xl s
xs' = fmap Set.fromList xl'
instance CanSubst Type where
basicSubst ty s =
case Map.lookup ty c of
Just ty' -> (ty',s)
Nothing ->
(ty', TypeSubst m (Map.insert ty ty' c'))
where
(ty', TypeSubst m c') = dataSubst (Type.dest ty) s
where
TypeSubst _ c = s
instance CanSubst Var where
basicSubst (Var n ty) s =
(fmap (Var n) ty', s')
where
(ty',s') = basicSubst ty s
compose :: TypeSubst -> TypeSubst -> TypeSubst
compose sub1 sub2 | HOL.TypeSubst.null sub2 = sub1
compose sub1 sub2 | HOL.TypeSubst.null sub1 = sub2
compose sub1 sub2 | otherwise =
mk $ fst $ Map.foldrWithKey inc (dest sub2, sub2) (dest sub1)
where
inc v1 t1 (m2,s2) = (m2',s2')
where
(t1',s2') = trySharingSubst t1 s2
m2' = Map.insert v1 t1' m2