module Data.Extensible.Internal (Membership
, getMemberId
, runMembership
, compareMembership
, ord
, NavHere(..)
, navigate
, here
, navNext
, navL
, navR
, (:*)(..)
, Member(..)
, remember
, (∈)()
, Nat(..)
, ToInt(..)
, Lookup
, ListIndex
, Assoc(..)
, AssocKeys
, Associate(..)
, LookupTree(..)
, Succ
, MapSucc
, Pred
, Div2
, Half
, Head
, Tail
, lemmaHalfTail
, lemmaMerging
, (++)()
, Map
, Merge
, Concat
, Check
, Expecting
, Missing
, Ambiguous
, module Data.Type.Equality
, module Data.Proxy
) where
import Data.Type.Equality
import Data.Proxy
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative
import Data.Word
#endif
import Control.Monad
import Unsafe.Coerce
import Data.Typeable
import Language.Haskell.TH hiding (Pred)
import Data.Bits
ord :: Int -> Q Exp
ord n = do
let names = map mkName $ take (n + 1) $ concatMap (flip replicateM ['a'..'z']) [1..]
let rest = mkName "any"
let cons x xs = PromotedConsT `AppT` x `AppT` xs
let t = foldr cons (VarT rest) (map VarT names)
sigE (conE 'Membership `appE` litE (IntegerL $ toInteger n))
$ forallT (PlainTV rest : map PlainTV names) (pure [])
$ conT ''Membership `appT` pure t `appT` varT (names !! n)
newtype Membership (xs :: [k]) (x :: k) = Membership { getMemberId :: Word } deriving Typeable
newtype Remembrance xs x r = Remembrance (Member xs x => r)
remember :: forall xs x r. Membership xs x -> (Member xs x => r) -> r
remember pos r = unsafeCoerce (Remembrance r :: Remembrance xs x r) pos
type family ListIndex (n :: Nat) (xs :: [k]) :: k where
ListIndex 'Zero (x ': xs) = x
ListIndex ('SDNat n) (y ': xs) = ListIndex n (Half xs)
ListIndex ('DNat n) xs = ListIndex n (Half xs)
type family Pred (n :: Nat) :: Nat where
Pred ('SDNat 'Zero) = 'Zero
Pred ('SDNat n) = 'DNat n
Pred ('DNat n) = 'SDNat (Pred n)
Pred 'Zero = 'Zero
type family Div2 (n :: Nat) :: Nat where
Div2 ('SDNat n) = n
Div2 ('DNat n) = n
Div2 'Zero = 'Zero
data Assoc k v = k :> v
type family AssocKeys (xs :: [Assoc k v]) :: [k] where
AssocKeys ((k ':> v) ': xs) = k ': AssocKeys xs
AssocKeys '[] = '[]
class Associate k v xs | k xs -> v where
association :: Membership xs (k ':> v)
instance (Check k (Lookup k (AssocKeys xs)) ~ Expecting one, ToInt one, (k ':> v) ~ ListIndex one xs) => Associate k v xs where
association = Membership (theInt (Proxy :: Proxy one))
data (h :: k -> *) :* (s :: [k]) where
Nil :: h :* '[]
Tree :: !(h x)
-> h :* Half xs
-> h :* Half (Tail xs)
-> h :* (x ': xs)
deriving instance Typeable (:*)
class LookupTree (n :: Nat) (xs :: [k]) x | n xs -> x where
lookupTree :: Functor f => proxy n
-> (h x -> f (h x))
-> h :* xs -> f (h :* xs)
instance LookupTree 'Zero (x ': xs) x where
lookupTree _ f (Tree h a b) = fmap (\h' -> Tree h' a b) (f h)
instance LookupTree n (Half xs) x => LookupTree ('SDNat n) (t ': xs) x where
lookupTree _ f (Tree h a b) = fmap (\a' -> Tree h a' b) (lookupTree (Proxy :: Proxy n) f a)
instance LookupTree (Pred n) (Half (Tail xs)) x => LookupTree ('DNat n) (t ': xs) x where
lookupTree _ f (Tree h a b) = fmap (\b' -> Tree h a b')
(lookupTree (Proxy :: Proxy (Div2 (Pred ('DNat n)))) (unsafeCoerce f) b)
instance Show (Membership xs x) where
show (Membership n) = "$(ord " ++ show n ++ ")"
instance Eq (Membership xs x) where
_ == _ = True
instance Ord (Membership xs x) where
compare _ _ = EQ
runMembership :: Membership (y ': xs) x -> (x :~: y -> r) -> (Membership xs x -> r) -> r
runMembership (Membership 0) l _ = l (unsafeCoerce Refl)
runMembership (Membership n) _ r = r (Membership (n 1))
compareMembership :: Membership xs x -> Membership xs y -> Either Ordering (x :~: y)
compareMembership (Membership m) (Membership n) = case compare m n of
EQ -> Right (unsafeCoerce Refl)
x -> Left x
navigate :: (NavHere xs x -> r)
-> (Membership (Half (Tail xs)) x -> r)
-> (Membership (Half (Tail (Tail xs))) x -> r)
-> Membership xs x
-> r
navigate h nl nr = \case
Membership 0 -> h (unsafeCoerce Here)
Membership n -> if n .&. 1 == 0
then nr (Membership (unsafeShiftR (n 1) 1))
else nl (Membership (unsafeShiftR (n 1) 1))
data NavHere xs x where
Here :: NavHere (x ': xs) x
here :: Membership (x ': xs) x
here = Membership 0
navNext :: Membership xs y -> Membership (x ': xs) y
navNext (Membership n) = Membership (n + 1)
navL :: Membership (Half xs) y -> Membership (x ': xs) y
navL (Membership x) = Membership (x * 2 + 1)
navR :: Membership (Half (Tail xs)) y -> Membership (x ': xs) y
navR (Membership x) = Membership (x * 2 + 2)
type x ∈ xs = Member xs x
type family Head (xs :: [k]) :: k where
Head (x ': xs) = x
class Member xs x where
membership :: Membership xs x
data Expecting a
data Missing a
data Ambiguous a
type family Check x xs where
Check x '[n] = Expecting n
Check x '[] = Missing x
Check x xs = Ambiguous x
instance (Check x (Lookup x xs) ~ Expecting one, ToInt one) => Member xs x where
membership = Membership (theInt (Proxy :: Proxy one))
type family Lookup (x :: k) (xs :: [k]) :: [Nat] where
Lookup x (x ': xs) = 'Zero ': Lookup x xs
Lookup x (y ': ys) = MapSucc (Lookup x ys)
Lookup x '[] = '[]
type family Half (xs :: [k]) :: [k] where
Half '[] = '[]
Half (x ': y ': zs) = x ': Half zs
Half (x ': '[]) = '[x]
type family Tail (xs :: [k]) :: [k] where
Tail (x ': xs) = xs
Tail '[] = '[]
data Nat = Zero | DNat Nat | SDNat Nat
class ToInt n where
theInt :: proxy n -> Word
instance ToInt 'Zero where
theInt _ = 0
instance ToInt n => ToInt ('DNat n) where
theInt _ = theInt (Proxy :: Proxy n) `unsafeShiftL` 1
instance ToInt n => ToInt ('SDNat n) where
theInt _ = (theInt (Proxy :: Proxy n) `unsafeShiftL` 1) + 1
type family Succ (x :: Nat) :: Nat where
Succ 'Zero = 'SDNat 'Zero
Succ ('DNat n) = 'SDNat n
Succ ('SDNat n) = 'DNat (Succ n)
type family MapSucc (xs :: [Nat]) :: [Nat] where
MapSucc '[] = '[]
MapSucc (x ': xs) = Succ x ': MapSucc xs
lemmaHalfTail :: proxy xs -> p (x ': Half (Tail xs)) -> p (Half (x ': xs))
lemmaHalfTail _ = unsafeCoerce
lemmaMerging :: p (Merge (Half xs) (Half (Tail xs))) -> p xs
lemmaMerging = unsafeCoerce
type family Map (f :: k -> k) (xs :: [k]) :: [k] where
Map f '[] = '[]
Map f (x ': xs) = f x ': Map f xs
type family (++) (xs :: [k]) (ys :: [k]) :: [k] where
'[] ++ ys = ys
(x ': xs) ++ ys = x ': xs ++ ys
infixr 5 ++
type family Concat (xs :: [[k]]) :: [k] where
Concat '[] = '[]
Concat (x ': xs) = x ++ Concat xs
type family Merge (xs :: [k]) (ys :: [k]) :: [k] where
Merge (x ': xs) (y ': ys) = x ': y ': Merge xs ys
Merge xs '[] = xs
Merge '[] ys = ys