{-# OPTIONS -fglasgow-exts #-}
module Perm (tests) where
import Test.HUnit
import Control.Monad
import Data.Generics
data T1 = T1 deriving (Show, Eq, Typeable, Data)
data T2 = T2 deriving (Show, Eq, Typeable, Data)
data T3 = T3 T1 T2 deriving (Show, Eq, Typeable, Data)
newtype ReadT a = ReadT { unReadT :: [String] -> Maybe ([String],a) }
runReadT x y = case unReadT x y of
Just ([],y) -> Just y
_ -> Nothing
readT :: ReadT String
readT = ReadT (\x -> if null x
then Nothing
else Just (tail x, head x)
)
instance Monad ReadT where
return x = ReadT (\y -> Just (y,x))
c >>= f = ReadT (\x -> case unReadT c x of
Nothing -> Nothing
Just (x', a) -> unReadT (f a) x'
)
instance MonadPlus ReadT where
mzero = ReadT (const Nothing)
f `mplus` g = ReadT (\x -> case unReadT f x of
Nothing -> unReadT g x
y -> y
)
newtype GenM = GenM { unGenM :: forall a. Data a => a -> ReadT a }
buildT :: forall a. Data a => ReadT a
buildT = result
where
result = do str <- readT
con <- string2constr str
ske <- return $ fromConstr con
fs <- return $ gmapQ buildT' ske
perm [] fs ske
myType = myTypeOf result
where
myTypeOf :: forall a. ReadT a -> a
myTypeOf = undefined
string2constr str = maybe mzero
return
(readConstr (dataTypeOf myType) str)
buildT' :: forall a. Data a => a -> GenM
buildT' (_::a) = GenM (const mzero `extM` const (buildT::ReadT a))
perm :: forall a. Data a => [GenM] -> [GenM] -> a -> ReadT a
perm [] [] a = return a
perm fs [] a = perm [] fs a
perm fs (f:fs') a = (
do a' <- gmapMo (unGenM f) a
perm fs fs' a'
)
`mplus`
(
do guard (not (null fs'))
perm (f:fs) fs' a
)
tests =
( runReadT buildT ["T1"] :: Maybe T1
, ( runReadT buildT ["T2"] :: Maybe T2
, ( runReadT buildT ["T3","T1","T2"] :: Maybe T3
, ( runReadT buildT ["T3","T2","T1"] :: Maybe T3
, ( runReadT buildT ["T3","T2","T2"] :: Maybe T3
))))) ~=? output
output = (Just T1,(Just T2,(Just (T3 T1 T2),(Just (T3 T1 T2),Nothing))))