{-# LANGUAGE DefaultSignatures
, FlexibleContexts
, FlexibleInstances
, GADTs
, MultiParamTypeClasses
, ScopedTypeVariables
, TypeOperators
#-}
module Unbound.Generics.LocallyNameless.Subst (
SubstName(..)
, SubstCoerce(..)
, Subst(..)
) where
import GHC.Generics
import Data.List (find)
import Unbound.Generics.LocallyNameless.Name
import Unbound.Generics.LocallyNameless.Alpha
import Unbound.Generics.LocallyNameless.Embed
import Unbound.Generics.LocallyNameless.Shift
import Unbound.Generics.LocallyNameless.Bind
import Unbound.Generics.LocallyNameless.Rebind
import Unbound.Generics.LocallyNameless.Rec
data SubstName a b where
SubstName :: (a ~ b) => Name a -> SubstName a b
data SubstCoerce a b where
SubstCoerce :: Name b -> (b -> Maybe a) -> SubstCoerce a b
class Subst b a where
isvar :: a -> Maybe (SubstName a b)
isvar _ = Nothing
isCoerceVar :: a -> Maybe (SubstCoerce a b)
isCoerceVar _ = Nothing
subst :: Name b -> b -> a -> a
default subst :: (Generic a, GSubst b (Rep a)) => Name b -> b -> a -> a
subst n u x =
if (isFreeName n)
then case (isvar x :: Maybe (SubstName a b)) of
Just (SubstName m) -> if m == n then u else x
Nothing -> case (isCoerceVar x :: Maybe (SubstCoerce a b)) of
Just (SubstCoerce m f) -> if m == n then maybe x id (f u) else x
Nothing -> to $ gsubst n u (from x)
else error $ "Cannot substitute for bound variable " ++ show n
substs :: [(Name b, b)] -> a -> a
default substs :: (Generic a, GSubst b (Rep a)) => [(Name b, b)] -> a -> a
substs ss x
| all (isFreeName . fst) ss =
case (isvar x :: Maybe (SubstName a b)) of
Just (SubstName m) ->
case find ((==m) . fst) ss of
Just (_, u) -> u
Nothing -> x
Nothing -> case isCoerceVar x :: Maybe (SubstCoerce a b) of
Just (SubstCoerce m f) ->
case find ((==m) . fst) ss of
Just (_, u) -> maybe x id (f u)
Nothing -> x
Nothing -> to $ gsubsts ss (from x)
| otherwise =
error $ "Cannot substitute for bound variable in: " ++ show (map fst ss)
class GSubst b f where
gsubst :: Name b -> b -> f c -> f c
gsubsts :: [(Name b, b)] -> f c -> f c
instance Subst b c => GSubst b (K1 i c) where
gsubst nm val = K1 . subst nm val . unK1
gsubsts ss = K1 . substs ss . unK1
instance GSubst b f => GSubst b (M1 i c f) where
gsubst nm val = M1 . gsubst nm val . unM1
gsubsts ss = M1 . gsubsts ss . unM1
instance GSubst b U1 where
gsubst _nm _val _ = U1
gsubsts _ss _ = U1
instance GSubst b V1 where
gsubst _nm _val = id
gsubsts _ss = id
instance (GSubst b f, GSubst b g) => GSubst b (f :*: g) where
gsubst nm val (f :*: g) = gsubst nm val f :*: gsubst nm val g
gsubsts ss (f :*: g) = gsubsts ss f :*: gsubsts ss g
instance (GSubst b f, GSubst b g) => GSubst b (f :+: g) where
gsubst nm val (L1 f) = L1 $ gsubst nm val f
gsubst nm val (R1 g) = R1 $ gsubst nm val g
gsubsts ss (L1 f) = L1 $ gsubsts ss f
gsubsts ss (R1 g) = R1 $ gsubsts ss g
instance Subst b Int where subst _ _ = id ; substs _ = id
instance Subst b Bool where subst _ _ = id ; substs _ = id
instance Subst b () where subst _ _ = id ; substs _ = id
instance Subst b Char where subst _ _ = id ; substs _ = id
instance Subst b Float where subst _ _ = id ; substs _ = id
instance Subst b Double where subst _ _ = id ; substs _ = id
instance Subst b Integer where subst _ _ = id ; substs _ = id
instance (Subst c a, Subst c b) => Subst c (a,b)
instance (Subst c a, Subst c b, Subst c d) => Subst c (a,b,d)
instance (Subst c a, Subst c b, Subst c d, Subst c e) => Subst c (a,b,d,e)
instance (Subst c a, Subst c b, Subst c d, Subst c e, Subst c f) =>
Subst c (a,b,d,e,f)
instance (Subst c a) => Subst c [a]
instance (Subst c a) => Subst c (Maybe a)
instance (Subst c a, Subst c b) => Subst c (Either a b)
instance Subst b (Name a) where subst _ _ = id ; substs _ = id
instance Subst b AnyName where subst _ _ = id ; substs _ = id
instance (Subst c a) => Subst c (Embed a)
instance (Subst c e) => Subst c (Shift e) where
subst x b (Shift e) = Shift (subst x b e)
substs ss (Shift e) = Shift (substs ss e)
instance (Subst c b, Subst c a, Alpha a, Alpha b) => Subst c (Bind a b)
instance (Subst c p1, Subst c p2) => Subst c (Rebind p1 p2)
instance (Subst c p) => Subst c (Rec p)
instance (Alpha p, Subst c p) => Subst c (TRec p)