{-# OPTIONS -fglasgow-exts #-}
module Polymatch () where
import Data.Typeable
import Data.Generics
kids x = gmapQ Kid x
type Kids = [Kid]
data Kid = forall k. Typeable k => Kid k
fromConstrL :: Data a => Kids -> Constr -> Maybe a
fromConstrL l = unIDL . gunfold k z
where
z c = IDL (Just c) l
k (IDL Nothing _) = IDL Nothing undefined
k (IDL (Just f) (Kid x:l)) = IDL f' l
where
f' = case cast x of
(Just x') -> Just (f x')
_ -> Nothing
data IDL x = IDL (Maybe x) Kids
unIDL (IDL mx _) = mx
data A = A String deriving (Read, Show, Eq, Data, Typeable)
data B = B String deriving (Read, Show, Eq, Data, Typeable)
f :: (Data a, Data b, Show a, Read b)
=> (a->b) -> Either String a -> Either String b
f g (Right a) = Right $ g a
f g s = just (shallow_rebuild s)
just = maybe (error "tried, but failed.") id
deep_rebuild :: (Show a, Read b) => a -> b
deep_rebuild = read . show
shallow_rebuild :: (Data a, Data b) => a -> Maybe b
shallow_rebuild a = b
where
b = fromConstrL (kids a) constr
constr = indexConstr (dataTypeOf b) (constrIndex (toConstr a))
a2b (A s) = B s
t1 = f a2b (Left "x")
t2 = f a2b (Right (A "y"))