{-# LANGUAGE TypeOperators, PolyKinds, DataKinds, KindSignatures,
TypeFamilies, UndecidableInstances, MultiParamTypeClasses,
FlexibleInstances, GADTs, FlexibleContexts, ScopedTypeVariables,
ConstraintKinds, IncoherentInstances #-}
module Data.Type.Map (Mapping(..), Union, Unionable, union, Var(..), Map(..),
Combine, Combinable(..), Cmp,
Nubable, nub,
Lookup, Member, (:\), Split, split,
IsMember, lookp, Updatable, update,
IsMap, AsMap, asMap,
Submap, submap) where
import GHC.TypeLits
import Data.Type.Bool
import Data.Type.Equality
import Data.Type.Set (Cmp, Proxy(..), Flag(..), Sort, Filter, (:++))
infixr 4 :->
data Mapping k v = k :-> v
type Union m n = Nub (Sort (m :++ n))
type family Nub t where
Nub '[] = '[]
Nub '[kvp] = '[kvp]
Nub ((k :-> v1) ': (k :-> v2) ': m) = Nub ((k :-> Combine v1 v2) ': m)
Nub (kvp1 ': kvp2 ': s) = kvp1 ': Nub (kvp2 ': s)
type family Combine (a :: v) (b :: v) :: v
type family (m :: [Mapping k v]) :\ (c :: k) :: [Mapping k v] where
'[] :\ k = '[]
((k :-> v) ': m) :\ k = m :\ k
(kvp ': m) :\ k = kvp ': (m :\ k)
type family Lookup (m :: [Mapping k v]) (c :: k) :: Maybe v where
Lookup '[] k = Nothing
Lookup ((k :-> v) ': m) k = Just v
Lookup (kvp ': m) k = Lookup m k
type family Member (c :: k) (m :: [Mapping k v]) :: Bool where
Member k '[] = False
Member k ((k :-> v) ': m) = True
Member k (kvp ': m) = Member k m
data Var (k :: Symbol) = Var
instance KnownSymbol k => Show (Var k) where
show = symbolVal
data Map (n :: [Mapping Symbol *]) where
Empty :: Map '[]
Ext :: Var k -> v -> Map m -> Map ((k :-> v) ': m)
class IsMember v t m where
lookp :: Var v -> Map m -> t
instance {-# OVERLAPS #-} IsMember v t ((v ':-> t) ': m) where
lookp _ (Ext _ x _) = x
instance {-# OVERLAPPABLE #-} IsMember v t m => IsMember v t (x ': m) where
lookp v (Ext _ _ m) = lookp v m
class Updatable v t m n where
update :: Map m -> Var v -> t -> Map n
instance {-# OVERLAPS #-} Updatable v t ((v ':-> s) ': m) ((v ':-> t) ': m) where
update (Ext v _ m) _ x = Ext v x m
instance Updatable v t m n => Updatable v t ((w ':-> y) ': m) ((w ':-> y) ': n) where
update (Ext w y m) v x = Ext w y (update m v x)
instance Updatable v t s ((v ':-> t) ': s) where
update xs v x = Ext v x xs
type IsMap s = (s ~ Nub (Sort s))
type AsMap s = Nub (Sort s)
asMap :: (Sortable s, Nubable (Sort s)) => Map s -> Map (AsMap s)
asMap x = nub (quicksort x)
instance Show (Map '[]) where
show Empty = "{}"
instance (KnownSymbol k, Show v, Show' (Map s)) => Show (Map ((k :-> v) ': s)) where
show (Ext k v s) = "{" ++ show k ++ " :-> " ++ show v ++ show' s ++ "}"
class Show' t where
show' :: t -> String
instance Show' (Map '[]) where
show' Empty = ""
instance (KnownSymbol k, Show v, Show' (Map s)) => Show' (Map ((k :-> v) ': s)) where
show' (Ext k v s) = ", " ++ show k ++ " :-> " ++ show v ++ (show' s)
instance Eq (Map '[]) where
Empty == Empty = True
instance (Eq v, Eq (Map s)) => Eq (Map ((k :-> v) ': s)) where
(Ext Var v m) == (Ext Var v' m') = v == v' && m == m'
instance Ord (Map '[]) where
compare Empty Empty = EQ
instance (Ord v, Ord (Map s)) => Ord (Map ((k :-> v) ': s)) where
compare (Ext Var v m) (Ext Var v' m') = compare v v' `mappend` compare m m'
union :: (Unionable s t) => Map s -> Map t -> Map (Union s t)
union s t = nub (quicksort (append s t))
type Unionable s t = (Nubable (Sort (s :++ t)), Sortable (s :++ t))
append :: Map s -> Map t -> Map (s :++ t)
append Empty x = x
append (Ext k v xs) ys = Ext k v (append xs ys)
type instance Cmp (k :: Symbol) (k' :: Symbol) = CmpSymbol k k'
type instance Cmp (k :-> v) (k' :-> v') = CmpSymbol k k'
class Sortable xs where
quicksort :: Map xs -> Map (Sort xs)
instance Sortable '[] where
quicksort Empty = Empty
instance (Sortable (Filter FMin (k :-> v) xs)
, Sortable (Filter FMax (k :-> v) xs)
, FilterV FMin k v xs
, FilterV FMax k v xs) => Sortable ((k :-> v) ': xs) where
quicksort (Ext k v xs) =
quicksort (less k v xs) `append` Ext k v Empty `append` quicksort (more k v xs)
where
less = filterV (Proxy::(Proxy FMin))
more = filterV (Proxy::(Proxy FMax))
class FilterV (f::Flag) k v xs where
filterV :: Proxy f -> Var k -> v -> Map xs -> Map (Filter f (k :-> v) xs)
instance FilterV f k v '[] where
filterV _ k v Empty = Empty
instance (Conder (Cmp x (k :-> v) == LT), FilterV FMin k v xs) => FilterV FMin k v (x ': xs) where
filterV f@Proxy k v (Ext k' v' xs) =
cond (Proxy::(Proxy (Cmp x (k :-> v) == LT)))
(Ext k' v' (filterV f k v xs))
(filterV f k v xs)
instance
(Conder ((Cmp x (k :-> v) == GT) || (Cmp x (k :-> v) == EQ)), FilterV FMax k v xs)
=> FilterV FMax k v (x ': xs) where
filterV f@Proxy k v (Ext k' v' xs) =
cond (Proxy::(Proxy ((Cmp x (k :-> v) == GT) || (Cmp x (k :-> v) == EQ))))
(Ext k' v' (filterV f k v xs))
(filterV f k v xs)
class Combinable t t' where
combine :: t -> t' -> Combine t t'
class Nubable t where
nub :: Map t -> Map (Nub t)
instance Nubable '[] where
nub Empty = Empty
instance Nubable '[e] where
nub (Ext k v Empty) = Ext k v Empty
instance {-# OVERLAPPABLE #-}
(Nub (e ': f ': s) ~ (e ': Nub (f ': s)),
Nubable (f ': s)) => Nubable (e ': f ': s) where
nub (Ext k v (Ext k' v' s)) = Ext k v (nub (Ext k' v' s))
instance {-# OVERLAPS #-}
(Combinable v v', Nubable ((k :-> Combine v v') ': s))
=> Nubable ((k :-> v) ': (k :-> v') ': s) where
nub (Ext k v (Ext k' v' s)) = nub (Ext k (combine v v') s)
class Conder g where
cond :: Proxy g -> Map s -> Map t -> Map (If g s t)
instance Conder True where
cond _ s t = s
instance Conder False where
cond _ s t = t
class Split s t st where
split :: Map st -> (Map s, Map t)
instance Split '[] '[] '[] where
split Empty = (Empty, Empty)
instance {-# OVERLAPPABLE #-} Split s t st => Split (x ': s) (x ': t) (x ': st) where
split (Ext k v st) = let (s, t) = split st
in (Ext k v s, Ext k v t)
instance {-# OVERLAPS #-} Split s t st => Split (x ': s) t (x ': st) where
split (Ext k v st) = let (s, t) = split st
in (Ext k v s, t)
instance {-# OVERLAPS #-} (Split s t st) => Split s (x ': t) (x ': st) where
split (Ext k v st) = let (s, t) = split st
in (s, Ext k v t)
class Submap s t where
submap :: Map t -> Map s
instance Submap '[] '[] where
submap xs = Empty
instance {-# OVERLAPPABLE #-} Submap s t => Submap s (x ': t) where
submap (Ext _ _ xs) = submap xs
instance {-# OVERLAPS #-} Submap s t => Submap (x ': s) (x ': t) where
submap (Ext k v xs) = Ext k v (submap xs)