module Generics.RepLib.R where
import Unsafe.Coerce
import Data.Type.Equality
data R a where
Int :: R Int
Char :: R Char
Integer :: R Integer
Float :: R Float
Double :: R Double
Rational :: R Rational
IOError :: R IOError
IO :: (Rep a) => R a -> R (IO a)
Arrow :: (Rep a, Rep b) => R a -> R b -> R (a -> b)
Data :: DT -> [Con R a] -> R a
Abstract :: DT -> R a
#if MIN_VERSION_base(4,7,0)
Equal :: (Rep a, Rep b) => R a -> R b -> R (a :~: b)
#else
Equal :: (Rep a, Rep b) => R a -> R b -> R (a :=: b)
#endif
data Con r a where
Con :: Emb l a -> MTup r l -> Con r a
data Emb l a = Emb { to :: l -> a,
from :: a -> Maybe l,
labels :: Maybe [String],
name :: String,
fixity :: Fixity
}
data Fixity = Nonfix
| Infix { prec :: Int }
| Infixl { prec :: Int }
| Infixr { prec :: Int }
data DT = forall l. DT String (MTup R l)
data Nil = Nil
data a :*: l = a :*: l
infixr 7 :*:
data MTup r l where
MNil :: MTup r Nil
(:+:) :: (Rep a) => r a -> MTup r l -> MTup r (a :*: l)
infixr 7 :+:
class Rep a where rep :: R a
withRep :: R a -> (Rep a => r) -> r
withRep = unsafeCoerce (flip ($) :: R a -> (R a -> r) -> r)
instance Show (R a) where
show Int = "Int"
show Char = "Char"
show Integer = "Integer"
show Float = "Float"
show Double = "Double"
show Rational= "Rational"
show (IO t) = "(IO " ++ show t ++ ")"
show IOError = "IOError"
show (Arrow r1 r2) =
"(" ++ (show r1) ++ " -> " ++ (show r2) ++ ")"
show (Data dt _) =
"(Data" ++ show dt ++ ")"
show (Abstract dt) =
"(Abstract" ++ show dt ++ ")"
show (Equal r1 r2) =
"(Equal" ++ show r1 ++ " " ++ show r2 ++ ")"
instance Show DT where
show (DT str reps) = str ++ show reps
instance Show (MTup R l) where
show MNil = ""
show (r :+: MNil) = show r
show (r :+: rs) = " " ++ show r ++ show rs
instance Eq (R a) where
_ == _ = True
instance Ord (R a) where
compare _ _ = EQ
instance Rep Int where rep = Int
instance Rep Char where rep = Char
instance Rep Integer where rep = Integer
instance Rep Float where rep = Float
instance Rep Double where rep = Double
instance Rep Rational where rep = Rational
instance Rep IOError where rep = IOError
instance Rep a => Rep (IO a) where rep = IO rep
instance (Rep a, Rep b) => Rep (a -> b) where rep = Arrow rep rep
#if MIN_VERSION_base(4,7,0)
instance (Rep a, Rep b) => Rep (a :~: b) where rep = Equal rep rep
#else
instance (Rep a, Rep b) => Rep (a :=: b) where rep = Equal rep rep
#endif
rUnitEmb :: Emb Nil ()
rUnitEmb = Emb { to = \Nil -> (),
from = \() -> Just Nil,
labels = Nothing,
name = "()",
fixity = Nonfix }
rUnit :: R ()
rUnit = Data (DT "()" MNil)
[Con rUnitEmb MNil]
instance Rep () where rep = rUnit
instance (Rep a, Rep b) => Rep (a,b) where
rep = rTup2
rTup2 :: forall a b. (Rep a, Rep b) => R (a,b)
rTup2 = let args = ((rep :: R a) :+: (rep :: R b) :+: MNil) in
Data (DT "(,)" args) [ Con rPairEmb args ]
rPairEmb :: Emb (a :*: b :*: Nil) (a,b)
rPairEmb =
Emb { to = \( t1 :*: t2 :*: Nil) -> (t1,t2),
from = \(a,b) -> Just (a :*: b :*: Nil),
labels = Nothing,
name = "(,)",
fixity = Nonfix
}
rList :: forall a. Rep a => R [a]
rList = Data (DT "[]" ((rep :: R a) :+: MNil))
[ Con rNilEmb MNil, Con rConsEmb ((rep :: R a) :+: rList :+: MNil) ]
rNilEmb :: Emb Nil [a]
rNilEmb = Emb { to = \Nil -> [],
from = \x -> case x of
(_:_) -> Nothing
[] -> Just Nil,
labels = Nothing,
name = "[]",
fixity = Nonfix
}
rConsEmb :: Emb (a :*: [a] :*: Nil) [a]
rConsEmb =
Emb {
to = (\ (hd :*: tl :*: Nil) -> (hd : tl)),
from = \x -> case x of
(hd : tl) -> Just (hd :*: tl :*: Nil)
[] -> Nothing,
labels = Nothing,
name = ":",
fixity = Nonfix
}
instance Rep a => Rep [a] where
rep = rList