HLearn-algebra-1.1.0.0: src/HLearn/Algebra/Types/Indexing.hs
{-# LANGUAGE DataKinds #-}
module HLearn.Algebra.Types.Indexing
(
Index(..)
, DepIndex(..)
, HasDepIndex(..)
, ValueList
-- ** template haskell
, makeIndex
-- ** dependent tuple indexing
, TH_0
, TH_1
, TH_2
, TH_3
)
where
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import HLearn.Algebra.Types.HList
-------------------------------------------------------------------------------
-- classes
-- | index into a data type, all of whose members have the same type
class
( Eq (IndexType datatype)
, Bounded (IndexType datatype)
, Enum (IndexType datatype)
) => Index datatype
where
type IndexType datatype
type IndexResult datatype
(!) :: datatype -> IndexType datatype -> IndexResult datatype
-- | index into a data type, but the result type depends on which record we're indexing
class DepIndex datatype index where
type DepIndexResult datatype index
(#) :: datatype -> index -> datatype `DepIndexResult` index
type family (#) datatype index
type instance (#) datatype index = DepIndexResult datatype index
instance DepIndex (HList '[]) (Nat1Box Zero) where
type DepIndexResult (HList '[]) (Nat1Box Zero) = ()
_ # _ = ()
instance DepIndex (HList (x ': xs)) (Nat1Box Zero) where
type DepIndexResult (HList (x ': xs)) (Nat1Box Zero) = x
(x:::xs) # _ = x
instance (DepIndex (HList xs) (Nat1Box n)) => DepIndex (HList (x ': xs)) (Nat1Box (Succ n)) where
type DepIndexResult (HList (x ': xs)) (Nat1Box (Succ n)) = DepIndexResult (HList xs) (Nat1Box n)
(x:::xs) # Nat1Box = xs # (Nat1Box :: Nat1Box n)
-- | defines a canonical ordering of all elments in the data type
class (IndexList datatype (HList (DepIndexList datatype))) => HasDepIndex datatype where
type DepIndexList datatype :: [*]
depIndexList :: datatype -> HList (DepIndexList datatype)
datatype2valueList ::
( HasDepIndex datatype
) => datatype -> HList (ValueList datatype)
datatype2valueList dp = valueList dp (depIndexList dp)
type ValueList datatype = IndexList2ValueList datatype (HList (DepIndexList datatype))
-- | this class exists only to ensure that all elements in the "DepIndexList" are actually valid "DepIndex"es
class IndexList dp indexL where
type IndexList2ValueList dp indexL :: [*]
valueList :: dp -> indexL -> HList (IndexList2ValueList dp indexL)
instance IndexList dp (HList '[]) where
type IndexList2ValueList dp (HList '[]) = '[]
{-`DepIndexResult` INLINE valueList `DepIndexResult`-}
valueList dp _ = HNil
instance
( IndexList dp (HList xs)
, DepIndex dp x
) => IndexList dp (HList (x ': xs))
where
type IndexList2ValueList dp (HList (x ': xs)) = (dp `DepIndexResult` x) ': (IndexList2ValueList dp (HList xs))
{-`DepIndexResult` INLINE valueList `DepIndexResult`-}
valueList dp (x:::xs) = dp # x ::: valueList dp xs
-------------------------------------------------------------------------------
-- template haskell
-- | Creates data types and instances for indexing into a class. Dependent indices are preficed with \"TH_\" and normal indices by \"I_\". The dependent indices and "DepIndex" instances are always created. The normal index data types are always created, but the "Index" instance is created only if all records within the data type have the same type.
makeIndex :: Name -> Q [Dec]
makeIndex datatype = do
d2 <- makeDepIndexData datatype
c2 <- makeDepIndexClass datatype
d1 <- makeIndexData datatype
xs <- extractConstructorFields datatype
let (_,_,t0) = head xs
c1 <- if fst $ foldr (\(_,_,t) (bool,t') -> (t==t' && bool,t)) (True,t0) xs
then makeIndexClass datatype
else return []
return $ d1++c1++d2++c2
makeIndexData :: Name -> Q [Dec]
makeIndexData datatype = do
xs <- extractFieldStrings datatype
return $ [
DataD
[]
(mkName $ "I_" ++ nameBase datatype)
[]
(map (\x -> NormalC (mkName $ "I_" ++ x) []) xs)
[mkName "Show",mkName "Read",mkName "Eq",mkName "Ord",mkName "Bounded",mkName "Enum"]
]
makeIndexClass :: Name -> Q [Dec]
makeIndexClass datatype = do
xs <- extractConstructorFields datatype
let (_,_,t) = head xs
return $ [
InstanceD
[]
-- (AppT (AppT (AppT
-- (ConT $ mkName "Index")
-- (ConT datatype))
-- (ConT $ mkName $ "I_"++nameBase datatype))
-- (t)
-- )
(AppT (ConT $ mkName "Index") (ConT datatype))
[ TySynInstD (mkName "IndexType" ) [ConT datatype] (ConT $ mkName $ "I_"++nameBase datatype)
, TySynInstD (mkName "IndexResult") [ConT datatype] t
, FunD
(mkName "!")
(map (\(x,_,_) -> Clause
[VarP $ mkName "datatype", ConP (mkName $ "I_"++nameBase x) []]
(NormalB $ AppE (VarE x) (VarE $ mkName "datatype"))
[]
) xs)
]
]
depIndexPrefix :: String
depIndexPrefix = "TH"
makeDepIndexData :: Name -> Q [Dec]
makeDepIndexData datatype = do
xs <- extractFieldStrings datatype
return $ map (\x ->
DataD
[]
(mkName $ depIndexPrefix++x)
[]
[NormalC (mkName $ depIndexPrefix++x) []]
[mkName "Show", mkName "Read", mkName "Eq", mkName "Ord"]
) xs
makeDepIndexClass :: Name -> Q [Dec]
makeDepIndexClass datatype = do
xs <- extractConstructorFields datatype
return $ map (\(x,_,t) ->
InstanceD
[]
-- (AppT (AppT (AppT
-- (ConT $ mkName "DepIndex")
-- (ConT datatype))
-- (ConT $ mkName $ depIndexPrefix++nameBase x)) (t)
-- )
(AppT (AppT (ConT $ mkName "DepIndex") (ConT datatype)) (ConT $ mkName $ depIndexPrefix++nameBase x))
[ TySynInstD (mkName "DepIndexResult") [ConT datatype, ConT $ mkName $ depIndexPrefix++nameBase x] t
, FunD
(mkName "#")
[ Clause
[VarP $ mkName "datatype", VarP $ mkName "index"]
(NormalB $ AppE (VarE x) (VarE $ mkName "datatype"))
[]
]
]
) xs
extractFieldStrings :: Name -> Q [String]
extractFieldStrings datatype = do
xs <- extractConstructorFields datatype
return $ do
(name,_,_) <- xs
return $ nameBase name
type ConstructorFieldInfo = (Name,Strict,Type)
extractConstructorFields :: Name -> Q [ConstructorFieldInfo]
extractConstructorFields datatype = do
let datatypeStr = nameBase datatype
i <- reify datatype
return $ case i of
TyConI (DataD _ _ _ [RecC _ fs] _) -> fs
TyConI (NewtypeD _ _ _ (RecC _ fs) _) -> fs
TyConI (DataD _ _ _ [_] _) -> error $ "Can't derive Lens without record selectors: " ++ datatypeStr
TyConI NewtypeD{} -> error $ "Can't derive Lens without record selectors: " ++ datatypeStr
TyConI TySynD{} -> error $ "Can't derive Lens for type synonym: " ++ datatypeStr
TyConI DataD{} -> error $ "Can't derive Lens for tagged union: " ++ datatypeStr
_ -> error $ "Can't derive Lens for: " ++ datatypeStr ++ ", type name required."
-------------------------------------------------------------------------------
-- tuples
data TH_0 = TH_0
data TH_1 = TH_1
data TH_2 = TH_2
data TH_3 = TH_3
data TH_4 = TH_4
data TH_5 = TH_5
data TH_6 = TH_6
data TH_7 = TH_7
data TH_8 = TH_8
data TH_9 = TH_9
instance DepIndex (a,b) TH_0 where
type (a,b) `DepIndexResult` TH_0 = a
(a,b) # TH_0 = a
instance DepIndex (a,b) TH_1 where
type (a,b) `DepIndexResult` TH_1 = b
(a,b) # TH_1 = b
instance (Ord a, Num a) => Index (a,a) where
type IndexType (a,a) = Int
type IndexResult (a,a) = a
(!) (a0,a1) 0 = a0
(!) (a0,a1) 1 = a1
instance DepIndex (a,b,c) TH_0 where
type (a,b,c) `DepIndexResult` TH_0 = a
(a,b,c) # TH_0 = a
instance DepIndex (a,b,c) TH_1 where
type (a,b,c) `DepIndexResult` TH_1 = b
(a,b,c) # TH_1 = b
instance DepIndex (a,b,c) TH_2 where
type (a,b,c) `DepIndexResult` TH_2 = c
(a,b,c) # TH_2 = c
instance (Ord a, Num a) => Index (a,a,a) where
type IndexType (a,a,a) = Int
type IndexResult (a,a,a) = a
(!) (a0,a1,a2) 0 = a0
(!) (a0,a1,a2) 1 = a1
(!) (a0,a1,a2) 2 = a2