fei-base-1.0.0: c-apis/MXNet/Base/Spec/HMap.hs
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE PolyKinds, DataKinds, TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ConstraintKinds #-}
module MXNet.Base.Spec.HMap where
import RIO
import GHC.TypeLits
import Data.Proxy
import Data.Typeable (Typeable)
import Data.Constraint (Dict(..))
import Type.Reflection (someTypeRep)
import Unsafe.Coerce (unsafeCoerce)
class Pair (p :: Symbol -> * -> *) where
key :: p k v -> Proxy k
value :: p k v -> v
data HMap (p :: Symbol -> * -> *) (kvs :: [*]) where
Nil :: Pair p => HMap p '[]
Cons :: Pair p => p k v -> HMap p kvs -> HMap p (p k v ': kvs)
infixr 0 .&
kv .& other = Cons kv other
class Access (b :: Bool) p k v kvs | k kvs -> v where
get' :: Proxy b -> HMap p kvs -> Proxy k -> v
instance Access True p k v (p k v ': kvs) where
get' _ (Cons pair _) _ = value pair
instance Access (MatchHead p k v kvs) p k v kvs => Access False p k v (kv ': kvs) where
get' _ (Cons _ n) k = get' (Proxy :: Proxy (MatchHead p k v kvs)) n k
get :: forall p k v kvs. Access (MatchHead p k v kvs) p k v kvs => HMap p kvs -> Proxy k -> v
get = get' (Proxy :: Proxy (MatchHead p k v kvs))
----
type family InHMap p k kvs :: Bool where
InHMap p k '[] = False
InHMap p k (p k v ': _) = True
InHMap p k (_ ': kvs) = InHMap p k kvs
type family MatchHead p k v kvs where
MatchHead p k v (p k v ': kvs) = True
MatchHead p k v (_ ': kvs) = False
MatchHead p k v '[] = False
type family MatchHeadKey p k kvs where
MatchHeadKey p k (p k v ': kvs) = True
MatchHeadKey p k (_ ': kvs) = False
MatchHeadKey p k '[] = False
-- class Query (b :: Bool) p k v kvs where
-- query' :: Proxy b -> HMap p kvs -> Proxy k -> Maybe v
-- instance Access (MatchHead p k v kvs) p k v kvs => Query True p k v kvs where
-- query' _ hmap key = Just $ hmap ! key
-- instance Query False p k v kvs where
-- query' _ hmap key = Nothing
class Query (b :: Bool) p k v kvs where
query' :: Proxy b -> HMap p kvs -> Proxy k -> Maybe v
instance Query True p k v (p k v ': kvs) where
query' _ (Cons pair _) key = Just (value pair)
instance Query False p k v '[] where
query' _ Nil key = Nothing
instance Query (MatchHead p k v kvs) p k v kvs => Query False p k v (kv ': kvs) where
query' _ (Cons _ n) key = query' (Proxy :: Proxy (MatchHead p k v kvs)) n key
query :: forall p k v kvs. Query (MatchHead p k v kvs) p k v kvs => HMap p kvs -> Proxy k -> Maybe v
query = query' (Proxy :: Proxy (MatchHead p k v kvs))
-- note this definition 'isJust (hmap !? key)' wouldn't work, because the result type cannot
-- be inferenced.
hasKey :: forall p (k :: Symbol) kvs. KnownSymbol k => HMap p kvs -> Proxy k -> Bool
hasKey hmap key = case axiomInHMapTypeable hmap key of
Dict -> someTypeRep (Proxy :: Proxy (InHMap p k kvs)) == someTypeRep (Proxy :: Proxy True)
-- pop one key from the HMap
class PopKey_ (b :: Bool) p k (kvs :: [*]) where
type PopResult_ b k kvs :: [*]
pop' :: Proxy b -> HMap p kvs -> Proxy k -> HMap p (PopResult_ b k kvs)
instance PopKey_ False p k '[] where
type PopResult_ False k '[] = '[]
pop' _ Nil _ = Nil
instance PopKey_ True p k (p k v ': kvs) where
type PopResult_ True k (p k v ': kvs) = kvs
pop' _ (Cons _ rest) _ = rest
instance PopKey_ (MatchHeadKey p k kvs) p k kvs => PopKey_ False p k (p k' v' ': kvs) where
type PopResult_ False k (p k' v' ': kvs) = p k' v' ': PopResult_ (MatchHeadKey p k kvs) k kvs
pop' _ (Cons pair rest) key = Cons pair (pop' (Proxy :: Proxy (MatchHeadKey p k kvs)) rest key)
type PopKey p kvs k = PopKey_ (MatchHeadKey p k kvs) p k kvs
type PopResult p kvs k = HMap p (PopResult_ (MatchHeadKey p k kvs) k kvs)
pop :: forall p (k :: Symbol) kvs. PopKey p kvs k => HMap p kvs -> Proxy k -> PopResult p kvs k
pop = pop' (Proxy :: Proxy (MatchHeadKey p k kvs))
axiomInHMapTypeable :: KnownSymbol k => HMap p kvs -> Proxy k -> Dict (Typeable (InHMap p k kvs))
axiomInHMapTypeable _ _ = unsafeCoerce (Dict :: Dict ())