{-# LANGUAGE ConstraintKinds
, DataKinds
, DefaultSignatures
, DeriveGeneric
, DerivingStrategies
, DerivingVia
, EmptyCase
, FlexibleContexts
, FlexibleInstances
, GADTs
, GeneralizedNewtypeDeriving
, InstanceSigs
, MultiParamTypeClasses
, PartialTypeSignatures
, ScopedTypeVariables
, StandaloneDeriving
, TupleSections
, TypeOperators
#-}
module Language.Nominal.Unify
(
KRen (..)
, Ren
, idRen
, nothingRen
, isJustRen
, isNothingRen
, renNub
, renExtend
, renToList
, renFromList
, renRemoveBlock
, KUnifyPerm (..)
, UnifyPerm
, unifyPerm
, kunifiablePerm
, unifiablePerm
, kevPrefixRen
, evPrefixRen
, kevIsPrefix
, evIsPrefix
) where
import Data.Function (on)
import qualified Data.Map.Strict as DM
import Data.Maybe
import Data.List.Extra (takeEnd)
import Data.List.NonEmpty (NonEmpty)
import Data.Proxy (Proxy (..))
import qualified Data.Set as S
import Data.Type.Equality
import GHC.Generics
import Type.Reflection
import Language.Nominal.Name
import Language.Nominal.NameSet
import Language.Nominal.Nom
import Language.Nominal.Binder
import Language.Nominal.Abs
newtype KRen s = Ren {unRen :: Maybe (DM.Map (KAtom s) (KAtom s))}
deriving (Show, Generic)
instance Typeable s => Swappable (KRen s) where
type Ren = KRen Tom
idRen :: KRen s
idRen = Ren . Just $ DM.empty
nothingRen :: KRen s
nothingRen = Ren Nothing
isJustRen :: KRen s -> Bool
isJustRen (Ren x) = isJust x
isNothingRen :: KRen s -> Bool
isNothingRen = not . isJustRen
instance Eq (KRen s) where
(==) = (==) `on` (unRen . renNub)
instance Ord (KRen s) where
compare = compare `on` unRen . renNub
instance Typeable s => KSupport s (KRen s) where
ksupp _ (Ren m') =
fromMaybe S.empty $
DM.foldrWithKey (\a b s -> if a == b then s else s `S.union` (S.fromList [a,b])) S.empty <$> m'
renNub :: KRen s -> KRen s
renNub (Ren m') = Ren $ DM.filterWithKey (/=) <$> m'
renExtend :: KAtom s -> KAtom s -> KRen s -> KRen s
renExtend a b (Ren m') = Ren $ do
m <- m'
case DM.lookup a m of
Nothing | not $ elem b $ DM.elems m -> DM.insert a b <$> m'
Just b' | b' == b -> m'
_ -> Nothing
renToList :: KRen s -> Maybe [(KAtom s, KAtom s)]
renToList (Ren Nothing) = Nothing
renToList (Ren (Just m)) = Just $ DM.toList m
renFromList :: [(KAtom s, KAtom s)] -> KRen s
renFromList = foldr (\(a,b) r -> renExtend a b r) idRen
renRemoveBlock :: [KAtom s] -> KRen s -> KRen s
renRemoveBlock _ (Ren Nothing) = Ren Nothing
renRemoveBlock atms (Ren (Just m)) =
DM.foldrWithKey (\a b r -> case (a `elem` atms, b `elem` atms) of
(True, True) -> r
(False, False) -> renExtend a b r
_ -> nothingRen
) idRen m
instance Semigroup (KRen s) where
(Ren (Just m)) <> r = DM.foldrWithKey renExtend r m
(Ren Nothing) <> _ = Ren Nothing
instance Monoid (KRen s) where
mempty = Ren $ Just DM.empty
instance Typeable s => KRestrict s (KRen s) where
restrict :: [KAtom s] -> KRen s -> KRen s
restrict as (Ren m') = Ren $ do
m <- m'
return $ DM.filterWithKey (\a b -> not (elem a as) && not (elem b as)) m
class KSupport s a => KUnifyPerm s a where
kunifyPerm :: proxy s -> a -> a -> KRen s
default kunifyPerm :: (Generic a, GUnifyPerm s (Rep a)) => proxy s -> a -> a -> KRen s
kunifyPerm _ x y = gunifyPerm (from x) (from y)
ren :: KRen s -> a -> a
default ren :: (Generic a, GUnifyPerm s (Rep a)) => KRen s -> a -> a
ren r = to . gren r . from
type UnifyPerm = KUnifyPerm Tom
unifyPerm :: UnifyPerm a => a -> a -> Ren
unifyPerm = kunifyPerm atTom
kunifiablePerm :: KUnifyPerm s a => proxy s -> a -> a -> Bool
kunifiablePerm p a a' = isJustRen $ kunifyPerm p a a'
unifiablePerm :: UnifyPerm a => a -> a -> Bool
unifiablePerm = kunifiablePerm atTom
instance (Typeable s, Eq a) => KUnifyPerm s (Nameless a) where
kunifyPerm _ a b
| a == b = mempty
| otherwise = Ren Nothing
ren _ = id
deriving via Nameless Bool instance Typeable s => KUnifyPerm s Bool
deriving via Nameless Int instance Typeable s => KUnifyPerm s Int
deriving via Nameless () instance Typeable s => KUnifyPerm s ()
deriving via Nameless Char instance Typeable s => KUnifyPerm s Char
instance (KUnifyPerm s a, KUnifyPerm s b) => KUnifyPerm s (a, b)
instance (KUnifyPerm s a, KUnifyPerm s b, KUnifyPerm s c) => KUnifyPerm s (a, b, c)
instance (KUnifyPerm s a, KUnifyPerm s b, KUnifyPerm s c, KUnifyPerm s d) => KUnifyPerm s (a, b, c, d)
instance (KUnifyPerm s a, KUnifyPerm s b, KUnifyPerm s c, KUnifyPerm s d, KUnifyPerm s e) => KUnifyPerm s (a, b, c, d, e)
instance KUnifyPerm s a => KUnifyPerm s [a]
instance KUnifyPerm s a => KUnifyPerm s (NonEmpty a)
instance KUnifyPerm s a => KUnifyPerm s (Maybe a)
instance (KUnifyPerm s a, KUnifyPerm s b) => KUnifyPerm s (Either a b)
instance (Typeable s, Typeable t) => KUnifyPerm s (KAtom t) where
kunifyPerm :: proxy s -> KAtom t -> KAtom t -> KRen s
kunifyPerm _ a b = case testEquality (typeRep :: TypeRep s) (typeRep :: TypeRep t) of
Nothing
| a == b -> mempty
| otherwise -> Ren Nothing
Just Refl -> renExtend a b mempty
ren :: KRen s -> KAtom t -> KAtom t
ren (Ren (Just m)) a =
case testEquality (typeRep :: TypeRep s) (typeRep :: TypeRep t) of
Nothing -> a
Just Refl -> DM.findWithDefault a a m
ren (Ren Nothing) a = a
instance (Typeable s, Typeable u, KUnifyPerm s t) => KUnifyPerm s (KName u t)
instance (Typeable s, KUnifyPerm s a) => KUnifyPerm s (KNom s a) where
kunifyPerm p noma nomb = resAppC' noma $ \a -> resAppC' nomb $ \b -> kunifyPerm p a b
ren r m = ren r <$> m
instance (Typeable s, KUnifyPerm s t, KUnifyPerm s a) => KUnifyPerm s (KAbs (KName s t) a) where
kunifyPerm p absa absb =
(fuse (absa, absb)) @@. \na (a,b) -> kunifyPerm p (na, a) (na, b)
ren r m = ren r <$> m
kevPrefixRen :: KUnifyPerm s a => proxy s -> [a] -> [a] -> KRen s
kevPrefixRen p l1 l2 = kunifyPerm p l1 (takeEnd (length l1) l2)
evPrefixRen :: UnifyPerm a => [a] -> [a] -> Ren
evPrefixRen = kevPrefixRen atTom
kevIsPrefix :: forall s proxy a. KUnifyPerm s a => proxy s -> [a] -> [a] -> Bool
kevIsPrefix p l1 l2 = isJustRen $ kevPrefixRen p l1 l2
evIsPrefix :: UnifyPerm a => [a] -> [a] -> Bool
evIsPrefix = kevIsPrefix atTom
class GUnifyPerm s f where
gunifyPerm :: f x -> f x -> KRen s
gren :: KRen s -> f x -> f x
instance GUnifyPerm s V1 where
gunifyPerm x = case x of
gren _ x = case x of
instance GUnifyPerm s U1 where
gunifyPerm U1 U1 = mempty
gren _ U1 = U1
instance (GUnifyPerm s f, GUnifyPerm s g) => GUnifyPerm s (f :*: g) where
gunifyPerm (x1 :*: y1) (x2 :*: y2) = gunifyPerm x1 x2 <> gunifyPerm y1 y2
gren r (x :*: y) = gren r x :*: gren r y
instance (GUnifyPerm s f, GUnifyPerm s g) => GUnifyPerm s (f :+: g) where
gunifyPerm (L1 x) (L1 y) = gunifyPerm x y
gunifyPerm (R1 x) (R1 y) = gunifyPerm x y
gunifyPerm _ _ = Ren Nothing
gren r (L1 x) = L1 $ gren r x
gren r (R1 x) = R1 $ gren r x
instance KUnifyPerm s c => GUnifyPerm s (K1 i c) where
gunifyPerm (K1 x) (K1 y) = kunifyPerm Proxy x y
gren r (K1 x) = K1 $ ren r x
instance GUnifyPerm s f => GUnifyPerm s (M1 i t f) where
gunifyPerm (M1 x) (M1 y) = gunifyPerm x y
gren r (M1 x) = M1 $ gren r x