{-# LANGUAGE UndecidableInstances, OverlappingInstances, Rank2Types,
CPP, KindSignatures, MultiParamTypeClasses, EmptyDataDecls #-}
module Data.Generics.SYB.WithClass.Basics (
module Data.Typeable,
module Data.Generics.SYB.WithClass.Context,
module Data.Generics.SYB.WithClass.Basics
) where
#if MIN_VERSION_base(4,7,0)
import Data.Typeable hiding (Proxy)
#else
import Data.Typeable
#endif
import Data.Generics.SYB.WithClass.Context
#ifdef __HADDOCK__
data Proxy
#else
data Proxy (a :: * -> *)
#endif
class (Typeable a, Sat (ctx a)) => Data ctx a
where
gfoldl :: Proxy ctx
-> (forall b c. Data ctx b => w (b -> c) -> b -> w c)
-> (forall g. g -> w g)
-> a -> w a
gfoldl _ _ z = z
gunfold :: Proxy ctx
-> (forall b r. Data ctx b => c (b -> r) -> c r)
-> (forall r. r -> c r)
-> Constr
-> c a
toConstr :: Proxy ctx -> a -> Constr
dataTypeOf :: Proxy ctx -> a -> DataType
gunfold _ _ _ _ = undefined
dataTypeOf _ _ = undefined
#if MIN_VERSION_base(4,11,0)
dataCast1 :: Typeable t
#else
dataCast1 :: Typeable1 t
#endif
=> Proxy ctx
-> (forall b. Data ctx b => w (t b))
-> Maybe (w a)
dataCast1 _ _ = Nothing
#if MIN_VERSION_base(4,11,0)
dataCast2 :: Typeable t
#else
dataCast2 :: Typeable2 t
#endif
=> Proxy ctx
-> (forall b c. (Data ctx b, Data ctx c) => w (t b c))
-> Maybe (w a)
dataCast2 _ _ = Nothing
type GenericT ctx = forall a. Data ctx a => a -> a
gmapT :: Proxy ctx -> GenericT ctx -> GenericT ctx
gmapT ctx f x = unID (gfoldl ctx k ID x)
where
k (ID g) y = ID (g (f y))
newtype ID x = ID { unID :: x }
type GenericM m ctx = forall a. Data ctx a => a -> m a
gmapM :: Monad m => Proxy ctx -> GenericM m ctx -> GenericM m ctx
gmapM ctx f = gfoldl ctx k return
where k c x = do c' <- c
x' <- f x
return (c' x')
type GenericQ ctx r = forall a. Data ctx a => a -> r
gmapQ :: Proxy ctx -> GenericQ ctx r -> GenericQ ctx [r]
gmapQ ctx f = gmapQr ctx (:) [] f
gmapQr :: Data ctx a
=> Proxy ctx
-> (r' -> r -> r)
-> r
-> GenericQ ctx r'
-> a
-> r
gmapQr ctx o r f x = unQr (gfoldl ctx k (const (Qr id)) x) r
where
k (Qr g) y = Qr (\s -> g (f y `o` s))
newtype Qr r a = Qr { unQr :: r -> r }
fromConstr :: Data ctx a => Proxy ctx -> Constr -> a
fromConstr ctx = fromConstrB ctx undefined
fromConstrB :: Data ctx a
=> Proxy ctx
-> (forall b. Data ctx b => b)
-> Constr
-> a
fromConstrB ctx f = unID . gunfold ctx k z
where
k c = ID (unID c f)
z = ID
fromConstrM :: (Monad m, Data ctx a)
=> Proxy ctx
-> (forall b. Data ctx b => m b)
-> Constr
-> m a
fromConstrM ctx f = gunfold ctx k z
where
k c = do { c' <- c; b <- f; return (c' b) }
z = return
data DataType = DataType
{ tycon :: String
, datarep :: DataRep
}
deriving Show
data Constr = Constr
{ conrep :: ConstrRep
, constring :: String
, confields :: [String]
, confixity :: Fixity
, datatype :: DataType
}
instance Show Constr where
show = constring
instance Eq Constr where
c == c' = constrRep c == constrRep c'
data DataRep = AlgRep [Constr]
| IntRep
| FloatRep
| StringRep
| NoRep
deriving (Eq,Show)
data ConstrRep = AlgConstr ConIndex
| IntConstr Integer
| FloatConstr Double
| StringConstr String
deriving (Eq,Show)
type ConIndex = Int
data Fixity = Prefix
| Infix
deriving (Eq,Show)
dataTypeName :: DataType -> String
dataTypeName = tycon
dataTypeRep :: DataType -> DataRep
dataTypeRep = datarep
constrType :: Constr -> DataType
constrType = datatype
constrRep :: Constr -> ConstrRep
constrRep = conrep
repConstr :: DataType -> ConstrRep -> Constr
repConstr dt cr =
case (dataTypeRep dt, cr) of
(AlgRep cs, AlgConstr i) -> cs !! (i-1)
(IntRep, IntConstr i) -> mkIntConstr dt i
(FloatRep, FloatConstr f) -> mkFloatConstr dt f
(StringRep, StringConstr str) -> mkStringConstr dt str
_ -> error "repConstr"
mkDataType :: String -> [Constr] -> DataType
mkDataType str cs = DataType
{ tycon = str
, datarep = AlgRep cs
}
mkConstr :: DataType -> String -> [String] -> Fixity -> Constr
mkConstr dt str fields fix =
Constr
{ conrep = AlgConstr idx
, constring = str
, confields = fields
, confixity = fix
, datatype = dt
}
where
idx = head [ i | (c,i) <- dataTypeConstrs dt `zip` [1..],
showConstr c == str ]
dataTypeConstrs :: DataType -> [Constr]
dataTypeConstrs dt = case datarep dt of
(AlgRep cons) -> cons
_ -> error "dataTypeConstrs"
constrFields :: Constr -> [String]
constrFields = confields
constrFixity :: Constr -> Fixity
constrFixity = confixity
showConstr :: Constr -> String
showConstr = constring
readConstr :: DataType -> String -> Maybe Constr
readConstr dt str =
case dataTypeRep dt of
AlgRep cons -> idx cons
IntRep -> mkReadCon (\i -> (mkPrimCon dt str (IntConstr i)))
FloatRep -> mkReadCon (\f -> (mkPrimCon dt str (FloatConstr f)))
StringRep -> Just (mkStringConstr dt str)
NoRep -> Nothing
where
mkReadCon :: Read t => (t -> Constr) -> Maybe Constr
mkReadCon f = case (reads str) of
[(t,"")] -> Just (f t)
_ -> Nothing
idx :: [Constr] -> Maybe Constr
idx cons = let fit = filter ((==) str . showConstr) cons
in if fit == []
then Nothing
else Just (head fit)
isAlgType :: DataType -> Bool
isAlgType dt = case datarep dt of
(AlgRep _) -> True
_ -> False
indexConstr :: DataType -> ConIndex -> Constr
indexConstr dt idx = case datarep dt of
(AlgRep cs) -> cs !! (idx-1)
_ -> error "indexConstr"
constrIndex :: Constr -> ConIndex
constrIndex con = case constrRep con of
(AlgConstr idx) -> idx
_ -> error "constrIndex"
maxConstrIndex :: DataType -> ConIndex
maxConstrIndex dt = case dataTypeRep dt of
AlgRep cs -> length cs
_ -> error "maxConstrIndex"
mkIntType :: String -> DataType
mkIntType = mkPrimType IntRep
mkFloatType :: String -> DataType
mkFloatType = mkPrimType FloatRep
mkStringType :: String -> DataType
mkStringType = mkPrimType StringRep
mkPrimType :: DataRep -> String -> DataType
mkPrimType dr str = DataType
{ tycon = str
, datarep = dr
}
mkPrimCon :: DataType -> String -> ConstrRep -> Constr
mkPrimCon dt str cr = Constr
{ datatype = dt
, conrep = cr
, constring = str
, confields = error $ concat ["constrFields : ", (tycon dt), " is primative"]
, confixity = error "constrFixity"
}
mkIntConstr :: DataType -> Integer -> Constr
mkIntConstr dt i = case datarep dt of
IntRep -> mkPrimCon dt (show i) (IntConstr i)
_ -> error "mkIntConstr"
mkFloatConstr :: DataType -> Double -> Constr
mkFloatConstr dt f = case datarep dt of
FloatRep -> mkPrimCon dt (show f) (FloatConstr f)
_ -> error "mkFloatConstr"
mkStringConstr :: DataType -> String -> Constr
mkStringConstr dt str = case datarep dt of
StringRep -> mkPrimCon dt str (StringConstr str)
_ -> error "mkStringConstr"
mkNorepType :: String -> DataType
mkNorepType str = DataType
{ tycon = str
, datarep = NoRep
}
isNorepType :: DataType -> Bool
isNorepType dt = case datarep dt of
NoRep -> True
_ -> False