Commits

Jean-Marie Gaillourdet committed 0cf868f

imported version 0.2.1 from Hackage

Comments (0)

Files changed (10)

+Name:		Agata
+version:	0.2.1
+cabal-Version:  >= 1.6
+build-type:     Simple
+license:        BSD3
+copyright:      Jonas Duregård
+license-file:   LICENSE
+author:		Jonas Duregård
+maintainer:     Jonas Duregård (jonas.duregard@gmail.com)
+category:	Testing
+synopsis:	Generator-generator for QuickCheck
+description:    Agata (Agata Generates Algebraic Types Automatically) uses Template Haskell to derive QuickCheck generators for Haskell data types.
+extra-source-files: Example.hs
+
+
+Library
+  Build-Depends: 
+    mtl, base>=4&&<5, 
+    template-haskell<2.5, 
+    QuickCheck>=2.1&&<2.2, 
+    containers, 
+    tagged==0.0
+  Exposed-modules:
+    Test.Agata,
+    Test.AgataTH,
+    Test.Agata.Common
+    Test.Agata.Strategies,
+    Test.Agata.Instances,
+    Test.Agata.Base
+    
+source-repository head
+  type:     darcs
+  location: http://patch-tag.com/r/jonas_duregard/Agata/
+{-#LANGUAGE TemplateHaskell #-}
+import Test.QuickCheck
+import Test.AgataTH
+
+data X a b = X [Either a b] deriving Show
+data Y = Y deriving Show
+data Z = Z deriving Show
+
+
+$(agatath $ derive ''X <++> NoArbitrary)
+instance (Buildable a, Buildable b) => Arbitrary (X a b) where
+ arbitrary = agataWith partitions
+
+
+$(agatath $ deriveall [''Y,''Z])
+
+main = sample (arbitrary :: Gen (X Y Z))
+Copyright (c) 2000-2006, Jonas Dureg�rd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, 
+  this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright 
+  notice, this list of conditions and the following disclaimer in the 
+  documentation and/or other materials provided with the distribution.
+- Neither the names of the copyright owners nor the names of the 
+  contributors may be used to endorse or promote products derived 
+  from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+import Distribution.Simple
+main = defaultMain
+module Test.Agata (
+    module Test.Agata.Base
+  , module Test.Agata.Strategies
+  , module Test.Agata.Common
+  , module Data.Tagged
+  ) where
+
+import Data.Tagged
+
+import Test.Agata.Base
+import Test.Agata.Strategies
+import Test.Agata.Common
+import Test.Agata.Instances

Test/Agata/Base.hs

+module Test.Agata.Base 
+    ( agata, agataWith, agataSC, agataEnum
+    , Buildable(..), Builder
+    , rebuild, rb, (>=>), (*>), ($>), (.>), graft, inline, automutrec
+    , use, construct, autorec, nonrec, mutrec, rec
+    ) where
+
+
+import Test.QuickCheck
+import Control.Monad.State.Lazy
+import Control.Monad (liftM2)
+import Control.Applicative((<$>))
+
+import Data.Maybe(mapMaybe)
+import Data.Tagged
+
+import Test.Agata.Common
+import Test.Agata.Strategies
+
+
+agata :: Buildable a => Gen a
+agata = agataWith linearSize
+
+agataWith :: Buildable a => Strategy a -> Gen a
+agataWith s = do
+  dist <- sized $ flip s dimension
+  evalImproving (dimension+1,0,[]) $ ii dist undefined
+  where
+    ii :: Buildable a => Improving () -> a -> Improving a
+    ii dist a = currentDimension >>= \lvl -> case unTagged lvl of
+      0 -> put (0,0,[]) >> realImp a
+      _ -> do
+        x <- realImp a 
+        dec
+        dist
+        ii dist x
+
+    dec = get >>= \(lvl,r,[]) -> put (lvl-1,r,[])
+
+
+evalImproving :: (Dimension a,Int,[Int]) -> Improving a -> Gen a
+evalImproving (d,k,ss) = flip evalStateT (unTagged d,k,ss)
+
+agataSC :: Buildable a => Int -> [a]
+agataSC = snd . agataEnum
+
+agataEnum :: Buildable a => Int -> (Integer,[a])
+agataEnum 0 = (toInteger $ length xs, xs) where 
+  xs = concat $ snd $ unzip [benum c 0|c<-build]
+agataEnum n
+ | n < 0 = (0,[])
+ | otherwise = (sum ms, concat xs) where 
+  (ms,xs) = unzip [benum c n|c<-build]
+
+
+
+
+
+class Buildable a where
+  build :: [Builder a]
+  improve :: a -> Improving a
+  improve = return
+  dimension :: Dimension a
+  dimension = autoDim
+
+data DB a = BuildDebug (Dimension a) [Builder a] deriving Show
+
+db :: Buildable a => DB a 
+db = BuildDebug dimension build
+
+rbuild :: Buildable a => Tagged a [Builder a]
+rbuild = return build
+
+data Builder a = MkBuilder {
+  bskel :: Int -> Improving a,
+  benter :: a, 
+  benum :: Int -> (Integer,[a]),
+  bfields :: [Recursivity a],
+  bweight :: Int
+  }
+
+instance Show (Builder a) where
+  show = show . bfields
+
+
+brec :: Builder a -> Dimension a -> Bool
+brec b d = d > 0 && (not . null $ filter (rc d) (bfields b))
+
+
+
+realBuild :: (Buildable a) => Int -> Improving a
+realBuild n = do
+  c <- currentDimension
+  let recs   = [bskel b n|b<- build, brec b c]
+  let nrecs  = [bskel b n|b<- build, not $ brec b c]
+  let exits   = [bskel b n|b<- build, brec b c, Rec `notElem` bfields b]
+  join (lift $ elements $ if n > 0 then 
+    if null recs then [get >>= error . show] else recs
+    else if null nrecs then recs else nrecs)
+      -- FIXME : Get exits
+      -- _ -> nrecs
+  
+
+
+-- Determines if a value is defined, should be defined, or left undefined
+realImp :: Buildable a => a -> Improving a
+realImp a = do
+  cur <- currentDimension
+  case compare (dimension `taggedWith` a) cur of
+     GT -> improve a
+     EQ -> if cur == 0 then realBuild 0 else unTagged (bacq a)
+     LT -> if (dimension `taggedWith` a) == cur - 1 then unTagged breq else return a
+
+breq :: Buildable a => Tagged a (Improving a)
+breq = isAlwaysRecursive >>= \b -> return $ if b then request >> return (error "1") else lift (elements (map benter build)) >>= improve
+
+bacq :: Buildable a => a -> Tagged a (Improving a)
+bacq a = isAlwaysRecursive >>= \b -> return $ if b then acquire >>= realBuild else improve a
+
+rebuild :: a -> (a -> Improving b) -> Improving b
+rebuild a f = f a 
+
+rb :: Buildable a => a -> (a->b) -> Improving b
+rb a f = f <$> realImp a
+
+
+data Recursivity a = 
+    NonRec (Dimension a) 
+  | Rec 
+  | MutRec 
+  | AutoMutRec (Dimension a) 
+  | AutoRec (Dimension a) 
+    deriving (Show,Eq)
+
+erc r = case r of
+       MutRec    -> True
+       Rec       -> True
+       AutoMutRec _ -> True
+       AutoRec _ -> False
+       NonRec _  -> False
+
+rc d r = case r of
+       MutRec    -> True
+       Rec       -> True
+       AutoMutRec n -> n >= fromIntegral d
+       AutoRec n -> n >= fromIntegral d
+       NonRec _  -> False
+
+isAlwaysRecursive :: Buildable a => Tagged a Bool
+isAlwaysRecursive =
+  any erc . concatMap bfields <$> rbuild
+
+
+-- A type that represents four possible computations on constructors
+--  Build a value with a list of sizes for recursive fields
+--  Collect informations about the fields of the constructor
+--  Enumerate all values to a specific depth
+--  Return a value where all fields are undefined
+data Application b a = 
+    Build (Improving (a,[Int]))
+  | Fields [Recursivity b]
+  | Enumerate Int Integer [a]
+  | Enter a
+
+a $> b = [construct a b]
+infixr 8 $>
+
+
+inline :: Buildable a => (a -> b) -> [Builder b]
+inline f = map trans build where
+  trans b = MkBuilder
+    (\n -> f <$> bskel b n)
+    (f $ benter b)
+    (\n -> if n <= 0 then (0,[]) else 
+             let (m1,ys) = agataEnum (n-1) in 
+               if m1 <= 0 then (0,[]) else (m1,[f a|a <- ys]))
+    (map refield $ bfields b)
+    (bweight b)
+    where 
+      refield r = case r of
+        MutRec    -> MutRec
+        Rec       -> Rec
+        AutoMutRec n -> AutoMutRec (retag n)
+        AutoRec n -> AutoRec (retag n)
+        NonRec n  -> NonRec (retag n)
+
+construct :: a -> (Application b a -> Application b b) -> Builder b
+construct c f = MkBuilder skel enter enm fields 1 where
+  fields = case f $ Fields [] of
+    Fields ls -> ls
+  recfields lev = filter (rc lev) fields
+  isrec lev = not $ null $ recfields lev
+  skel n        = do
+    rs <- length . recfields <$> currentDimension
+    ns <- if rs == 0 then return $ repeat 0 else lift $ piles rs (n-1)
+    let Build m = f (Build $ return (c,ns))
+    fst <$> m
+  enm n = case f $ Enumerate n 1 [c] of
+    Enumerate _ m ls -> (m,ls)
+  enter = case f $ Enter c of
+    Enter x -> x
+
+graft :: Gen a -> (Int -> (Integer,[a])) -> [Builder a]
+graft g e = [MkBuilder (lift . flip resize g) undefined e [MutRec] 1]
+
+use :: a -> [Builder a]
+use x = [construct x id]
+
+
+(.>) a b = b . a
+(*>) a b = a >=> b
+
+autoDim :: Buildable a => Dimension a
+autoDim = do 
+  r <- isAlwaysRecursive
+  if r then (+1) <$> maxdim else maxdim where
+    maxdim :: Buildable a => Dimension a
+    maxdim = (maximum . (0:)) <$> (rbuild >>= sequence . mapMaybe dimOf . concatMap bfields)  where
+      dimOf r = case r of
+        NonRec d  -> Just d
+        AutoRec d -> Just d
+        _         -> Nothing
+
+
+def :: Buildable a => Application c (a -> b) -> Application c b
+def (Enter f)          = Enter $ f (error "Entry-value")
+def (Enumerate n 0 []) = Enumerate n 0 []
+def (Enumerate n m xs) = Enumerate n (m1*m) [f a|f <- xs, a <- ys] where
+  (m1,ys) = agataEnum (n-1)
+
+
+mutrec :: Buildable a => Application c (a -> b) -> Application c b
+mutrec x = case x of
+  Fields xs -> Fields $ MutRec : xs
+  Build mf  -> Build $ do
+    (f,x:xs) <- mf
+    realBuild x >>= \e -> return (f e,xs)
+  _         -> def x
+
+rec :: Buildable c => Application c (c -> b) -> Application c b
+rec x = case x of
+  Fields xs -> Fields $ Rec : xs
+  _ -> mutrec x
+
+nonrec :: Buildable a => Application c (a -> b) -> Application c b
+nonrec x = case x of
+  Fields xs -> Fields $ NonRec (retag $ appDimension x) : xs
+  Build mf  -> Build $ do
+    (f,ns) <- mf
+    realImp undefined >>= \e -> return (f e,ns)
+  _         -> def x
+
+autorec :: Buildable a => Application c (a -> b) -> Application c b
+autorec x = case x of
+  Fields xs -> Fields $ AutoRec (retag $ appDimension x) : xs
+  Build mf  -> Build $ do
+    c <- currentDimension
+    let isRec = appDimension x >= c
+    if isRec then unbuild $ mutrec x else unbuild $ nonrec x
+    where
+      unbuild (Build x) = x
+  _         -> def x
+
+automutrec :: Buildable a => Application c (a -> b) -> Application c b
+automutrec x = case x of
+  Fields xs -> Fields $ AutoMutRec (retag $ appDimension x) : xs
+  _         -> autorec x
+
+appDimension :: Buildable a => Application c (a->b) -> Dimension a
+appDimension f = dimension
+
+
+

Test/Agata/Common.hs

+module Test.Agata.Common where
+
+
+import Test.QuickCheck
+
+import Control.Monad (liftM)
+import Control.Monad.State.Lazy
+
+import Data.Tagged
+
+
+type Dimension a = Tagged a Int
+
+instance Num b => Num (Tagged a b) where
+  (+) = liftM2 (+)
+  (*) = liftM2 (*)
+  (-) = liftM2 (-)
+  negate = liftM negate
+  abs = liftM abs
+  signum = liftM signum
+  fromInteger = return . fromInteger
+
+instance Real b => Real (Tagged a b) where
+  toRational = toRational . unTagged
+
+instance Integral b => Integral (Tagged a b) where
+  quot = liftM2 quot
+  rem = liftM2 rem
+  div = liftM2 div
+  mod = liftM2 mod
+  quotRem a b = unTagged $ liftM2 quotRem a b >>= \(x,y) -> return (return x,return y)
+  divMod a b = unTagged $ liftM2 divMod a b >>= \(x,y) -> return (return x,return y)
+  toInteger = toInteger . unTagged
+
+instance Enum b => Enum (Tagged a b) where
+  succ = liftM succ
+  pred = liftM pred
+  toEnum = return . toEnum
+  fromEnum = fromEnum . unTagged
+  enumFrom = map return . unTagged . liftM enumFrom
+  enumFromThen a = map return . unTagged . liftM2 enumFromThen a
+  enumFromTo a = map return . unTagged . liftM2 enumFromTo a
+  enumFromThenTo a b = map return . unTagged . liftM3 enumFromThenTo a b
+
+taggedWith :: Tagged b a -> b -> Tagged b a
+taggedWith = const
+
+type Improving a = StateT (Int, Int, [Int]) Gen a
+currentDimension :: Improving (Dimension a)
+currentDimension = return `fmap` getLevel where
+  getLevel :: Improving Int
+  getLevel = gets $ \(l,r,ss) -> l
+request :: Improving ()
+request = modify $ \(l,r,ss) -> (l,r+1,ss)
+acquire :: Improving Int
+acquire = do
+  get >>= check
+  (l,r,s:ss) <- get
+  put (l,r,ss)
+  return s
+  where
+    check s = case s of
+      (l,r,s:ss) -> return ()
+      _ -> error $ "acquire: " ++ show s
+
+
+piles 0 _      = return []
+piles a b 
+  | a <= 0     = error "piling 0 or fever piles"
+  | otherwise  = genSorted a b b >>= permute where
+  genSorted 1 n _ = return [n]
+  genSorted p n m = do 
+    r <- choose (ceiling $ fromIntegral  n / fromIntegral p,min m n)
+    liftM (r:) $ genSorted (p-1) (n-r) (min m r)
+
+permute :: [a] -> Gen [a]
+permute = fromList
+  where
+  fromList []  = return []
+  fromList [x] = return [x]
+  fromList xs  = fromList l `merge` fromList r
+      where (l,r) = splitAt (length xs `div` 2) xs
+  merge :: Gen [a] -> Gen [a] -> Gen [a]
+  merge rxs rys = do
+    xs <- rxs; ys <- rys
+    merge' (length xs, xs) (length ys, ys)
+   where
+    merge' (0 , [])   (_ , ys)   = return ys
+    merge' (_ , xs)   (0 , [])   = return xs
+    merge' (nx, x:xs) (ny, y:ys) = do
+      k <- choose (1,nx+ny)
+      if k <= nx
+        then (x:) `liftM` ((nx-1, xs) `merge'` (ny, y:ys))
+        else (y:) `liftM` ((nx, x:xs) `merge'` (ny-1, ys))
+        
+        

Test/Agata/Instances.hs

+module Test.Agata.Instances where
+
+import Test.Agata.Base
+
+import Test.QuickCheck (arbitrary)
+
+
+instance Buildable a => Buildable (Maybe a) where
+  improve x = case x of
+    Just a1 -> rebuild Just $ rb a1
+    _ -> return x
+  build =
+    use Nothing ++
+    Just $> autorec
+
+    
+
+instance (Buildable a, Buildable b) => Buildable (Either a b) where
+  improve x = case x of
+    Left a1 -> rebuild Left $ rb a1
+    Right a1 -> rebuild Right $ rb a1
+  build = 
+    Left $> autorec ++
+    Right $> autorec
+
+instance Buildable a => Buildable [a] where
+  improve x = case x of
+    (a:b) -> rebuild (:) $ rb a *> rb b
+    _     -> return x
+  build = 
+    use [] ++ 
+    (:)  $> autorec .> rec
+
+
+instance Buildable () where
+  improve x = case x of
+    _     -> return x
+  build = use ()
+    
+instance Buildable Bool where
+  improve x = case x of
+    _     -> return x
+  build = use True ++ use False
+
+
+instance Buildable Char where
+  dimension = return 0
+  improve x = case x of
+    _     -> return x
+  build = graft arbitrary (\n -> (toInteger (n+1),take (n+1) ['a'..'z'] ))
+
+      
+      
+instance Buildable Int where
+  dimension = return 1
+  improve x = case x of
+    _     -> return x
+  build = graft arbitrary (\n -> (toInteger (n+1),[0..n]) )
+
+
+
+
+
+
+
+
+instance (Buildable a,Buildable b) => Buildable (a,b) where
+  improve x = case x of
+    (a1, a2) -> rebuild (,) $ rb a1 *> rb a2
+  build = (,) $> autorec . autorec
+
+instance (Buildable a,Buildable b,Buildable c) => Buildable (a,b,c) where
+  improve x = case x of
+    (a1,a2,a3) -> 
+      rebuild (,,) $ rb a1 *> rb a2 *> rb a3
+  build =  (,,) $> autorec . autorec . autorec 
+
+
+instance (Buildable a,Buildable b,Buildable c,Buildable d) => Buildable (a,b,c,d) where
+  improve x = case x of
+    (a1,a2,a3,a4) -> 
+      rebuild (,,,) $ rb a1 *> rb a2 *> rb a3 *> rb a4
+  build = (,,,) $> autorec . autorec . autorec . autorec
+
+
+instance (Buildable a,Buildable b,Buildable c,Buildable d,Buildable e) => Buildable (a,b,c,d,e) where
+  improve x = case x of
+    (a1,a2,a3,a4,a5) -> 
+      rebuild (,,,,) $ rb a1 *> rb a2 *> rb a3 *> rb a4 *> rb a5
+  build = (,,,,) $> autorec . autorec . autorec . autorec . autorec
+
+
+instance (Buildable a,Buildable b,Buildable c,Buildable d,Buildable e,Buildable f) => Buildable (a,b,c,d,e,f) where
+  improve x = case x of
+    (a1,a2,a3,a4,a5,a6) -> 
+      rebuild (,,,,,) $ rb a1 *> rb a2 *> rb a3 *> rb a4 *> rb a5 *> rb a6 
+  build = (,,,,,) $> autorec . autorec . autorec . autorec . autorec . autorec 
+
+
+instance (Buildable a,Buildable b,Buildable c,Buildable d,Buildable e,Buildable f,Buildable g) => Buildable (a,b,c,d,e,f,g) where
+  improve x = case x of
+    (a1,a2,a3,a4,a5,a6,a7) -> 
+      rebuild (,,,,,,) $ rb a1 *> rb a2 *> rb a3 *> rb a4 *> rb a5 *> rb a6 *> rb a7 
+  build = (,,,,,,) $> autorec . autorec . autorec . autorec . autorec . autorec . autorec 
+
+
+instance (Buildable a,Buildable b,Buildable c,Buildable d,Buildable e,Buildable f,Buildable g,Buildable h) => Buildable (a,b,c,d,e,f,g,h) where
+  improve x = case x of
+    (a1,a2,a3,a4,a5,a6,a7,a8) -> 
+      rebuild (,,,,,,,) $ rb a1 *> rb a2 *> rb a3 *> rb a4 *> rb a5 *> rb a6 *> rb a7 *> rb a8
+  build = (,,,,,,,) $> autorec . autorec . autorec . autorec . autorec . autorec . autorec . autorec 
+
+
+instance (Buildable a,Buildable b,Buildable c,Buildable d,Buildable e,Buildable f,Buildable g,Buildable h,Buildable i) => Buildable (a,b,c,d,e,f,g,h,i) where
+  improve x = case x of
+    (a1,a2,a3,a4,a5,a6,a7,a8,a9) -> 
+      rebuild (,,,,,,,,) $ rb a1 *> rb a2 *> rb a3 *> rb a4 *> rb a5 *> rb a6 *> rb a7 *> rb a8 *> rb a9
+  build = (,,,,,,,,) $> autorec . autorec . autorec . autorec . autorec . autorec . autorec . autorec . autorec
+
+
+instance (Buildable a,Buildable b,Buildable c,Buildable d,Buildable e,Buildable f,Buildable g,Buildable h,Buildable i,Buildable j) => Buildable (a,b,c,d,e,f,g,h,i,j) where
+  improve x = case x of
+    (a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) -> 
+      rebuild (,,,,,,,,,) $ rb a1 *> rb a2 *> rb a3 *> rb a4 *> rb a5 *> rb a6 *> rb a7 *> rb a8 *> rb a9 *> rb a10
+  build = (,,,,,,,,,) $> autorec . autorec . autorec . autorec . autorec . autorec . autorec . autorec . autorec . autorec 
+

Test/Agata/Strategies.hs

+module Test.Agata.Strategies where
+
+import Test.QuickCheck
+import Control.Monad.State.Lazy
+import Test.Agata.Common
+
+
+type Strategy a = Int -> Dimension a -> Gen(Improving ())
+
+listStrategy :: (Int -> Dimension a -> Gen [Int]) -> Strategy a
+listStrategy f lev0 s = do
+    lvls <- f lev0 s
+    return $ do
+      (lvl,r,[]) <- get
+      let d = (lev0 - lvl) + 1
+      let k = lvls !! (lvl-1)
+      ms <- lift $ piles r k
+      put(lvl,0,ms) 
+
+
+linearSize :: Strategy a
+linearSize size _ = return $ do
+  (lvl,r,[]) <- get
+  ms <- lift $ piles (r+1) size
+  put(lvl,0,tail ms)
+  
+linearSize' :: Strategy a
+linearSize' size _ = return $ do
+  (lvl,r,[]) <- get
+  k <- lift $ choose (0,size)
+  ms <- lift $ piles r k
+  put(lvl,0,ms)
+
+quadraticSize :: Strategy a
+quadraticSize size lev0 = return $ do
+  (lvl,r,[]) <- get
+  k <- lift $ choose (0,size*((fromIntegral lev0 - lvl) + 1))
+  ms <- lift $ piles r k
+  put(lvl,0,ms) 
+
+quadraticSize' :: Strategy a
+quadraticSize' size lev0 = return $ do
+  (lvl,r,[]) <- get
+  ms <- lift $ piles (r+1) $ size*((fromIntegral lev0 - lvl) + 1)
+  put(lvl,0,ms) 
+
+partitions :: Strategy a
+partitions = listStrategy $ \s l -> do
+      xs <- sequence $ replicate (fromIntegral l-1) $ choose (0,s)
+      permute (s:xs)
+
+exponentialSize :: Strategy a
+exponentialSize s _ = return $ do 
+  (lvl,r,[]) <- get
+  ns <- sequence $ replicate r $ lift $ choose (0,s)
+  put (lvl,0,ns)
+
+fixedSize :: Strategy a
+fixedSize = listStrategy $ \s l -> piles (fromIntegral l) s
+  
+randomStrategy :: [Strategy a] -> Strategy a
+randomStrategy ls l s = oneof $ map (\f -> f l s) ls
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE CPP #-}
+
+-- {-
+module Test.AgataTH (
+      agatath
+    , derive, deriveall
+    , DerivOption(..), (<++>)
+    , echoAgata
+    , module Test.Agata
+    , module Test.QuickCheck
+    ) where
+-- }-
+-- module Test.AgataTH where
+
+import Language.Haskell.TH.Syntax hiding (lift)
+import qualified Language.Haskell.TH.Syntax as TH (lift)
+import Language.Haskell.TH
+import Control.Monad
+
+import Test.Agata
+import Test.QuickCheck(Arbitrary(..))
+
+import Data.List(nub, union)
+import Data.Maybe(fromMaybe)
+import qualified Data.Map as Map
+import qualified Data.Set as Set
+
+import Control.Monad.State.Lazy
+
+
+---------------------------------------------------------------------
+-- Some day this file might be tidied up into a presentable state...
+--   
+data Derivation = Derivation {
+    derivNames :: [Name]
+  , derivOptions :: Set.Set DerivOption
+  }
+
+data DerivOption = 
+    Inline Name
+  | NoArbitrary
+    deriving (Show,Eq,Ord)
+
+deriveall :: [Name] -> Derivation
+deriveall ns = Derivation ns Set.empty
+
+derive :: Name -> Derivation
+derive n = deriveall [n]
+
+
+
+
+
+(<++>) :: Derivation -> DerivOption -> Derivation
+(<++>) d o = d{derivOptions = o `Set.insert` derivOptions d}
+
+
+echoAgata s n =  agatath (derive  n) >>= (\r -> return [FunD (mkName s) [Clause [] (NormalB $ LitE $ StringL r)  []]]) . dump
+
+agatath :: Derivation -> Q [Dec]
+agatath der@(Derivation ts ss) = fmap concat $ mapM deriveAgata ts where
+  isSet o = o `Set.member` ss
+  deriveAgata n = do
+    i@(TyConI d)  <-  reify n
+  
+    nns <- replicateM (length $ dParams d) (newName "a")
+    nns1 <- replicateM (length $ dParams d) (newName "b") -- >>= mapM unVarBndr
+    let vs = map VarT nns
+    expanded <- fmap reTuple $ expand n nns1
+
+    m@[InstanceD [] (AppT (ConT cBuildable_) _) [ValD (VarP improve_) _ _,ValD (VarP build_) _ _,ValD (VarP dimension_) (NormalB (SigE (AppE rerelate_ _) (AppT tDimension_ _))) []]] <-
+       [d| instance Buildable T1 where
+             improve = undefined
+             build = undefined
+             dimension = retag dimension :: Dimension T1
+       |]
+
+    impbody <- mapM impClause (dConsts d)
+    buildbody <- fmap NormalB $ bldClauses (dConsts d) -- mapM (bldClause t) (dConsts d) >>= return . NormalB . ListE
+
+    allTypesT_t <- fmap (nub . concat) $ mapM (recs n . cFields) (dConsts d)
+  
+  
+    let 
+      isRecursive = Mut `elem` allTypesT_t
+      dimplus = InfixE (Just $ VarE dimension_)  (VarE $ mkName "+") (Just (LitE (IntegerL 1)))
+      dimtyp = ForallT (map varBndr nns1) [] $ AppT (AppT ArrowT (AppT tDimension_ expanded)) (AppT tDimension_ (getType n nns1))
+      dimbody = NormalB $ AppE (SigE rerelate_ dimtyp) (if isRecursive then dimplus else VarE dimension_)
+
+    let preqs = allInClass cBuildable_ vs
+
+    arb <- arbInstance preqs vs
+  
+    return $ [
+      InstanceD preqs (AppT (ConT cBuildable_) (rt vs n)) 
+        [FunD improve_ impbody
+        , ValD (VarP build_) buildbody []
+        , ValD (VarP dimension_) dimbody []
+        ]] ++ if isSet NoArbitrary then [] else [arb]
+  
+
+    where
+      rt :: [Type] -> Name -> Type
+      rt [] n = ConT n
+      rt (v:vs) n = AppT (rt vs n) v
+      genPE n = do
+        ids <- replicateM n (newName "x")
+        return (map varP ids, map varE ids)
+      
+      bldClauses [c]     = bldClause c
+      bldClauses (c:cs)  = [| $(bldClause c) ++ $(bldClauses cs) |]
+     
+      bldClause :: Con -> Q Exp
+      bldClause c 
+        | isSet $ Inline $ cName c =
+          [| inline $(conE $ cName c) |]
+        | otherwise               = do
+          let ts   = cFields c
+              name = cName c
+              f [] = [| id |]
+              f (Auto:vars) = [| autorec .> ($(f vars)) |]
+              f (Mut:vars) = [| automutrec .> ($(f vars)) |]
+          [| $(conE name) $> $(recs n ts >>= f) |]
+      
+      impClause c = do
+        let fields = cFields c
+        let name   = cName c
+        let idExp  = cId c
+        (pats,vars) <- genPE (length fields)
+        let f []       = [| return . id |]
+            f (v:vars) = [| rb $v *> $(f vars) |]
+        clause [conP name pats]                                 -- (A x1 x2)
+               (normalB [| rebuild $(idExp) $(f vars) |]) []  -- "A "++show x1++" "++show x2
+
+      arbInstance preqs vs = do
+        m@[InstanceD [] (AppT cArbitrary_ _) body_] <-
+          [d| instance Arbitrary T1 where
+                arbitrary = agata
+          |]
+        return $ InstanceD preqs (AppT cArbitrary_ (rt vs n)) body_
+
+data Recu = Mut | Auto deriving (Eq,Show)
+recs :: Name -> [Type] -> Q [Recu]
+recs n []     = return []
+recs n (t:ts) = do
+  ats <- allTypesT t
+  rest  <- recs n ts
+  return $ (if n `Set.member` ats then Mut else Auto) : rest
+
+
+allTypesT :: Type -> Q (Set.Set Name)
+allTypesT t = getCollected (xf t) where
+  f n1 = do
+    i <- lift $ reify n1
+    mapM_ xf (iTypes i)
+  xf :: Type -> Collecting Name ()
+  xf t = case t of
+        ConT n2	-> collectIf n2 (f n2)
+        AppT t1 t2  -> xf t1 >> xf t2 
+        VarT n	-> return ()
+        TupleT x	-> return ()
+        ArrowT	-> return ()         
+        ListT	-> return ()
+
+
+
+contains :: Type -> Name -> Q Bool
+contains t n = fmap (Set.member n) $ allTypesT t
+
+flat :: Type -> (Type,[Type])
+flat = flat' where
+  flat' (AppT t1 t2) = case flat' t1 of
+    (t,ts) -> (t,ts++[t2])
+  flat' x = (x,[])
+
+
+getType :: Name -> [Name] -> Type
+getType n [] = ConT n
+getType n (n1:ns) = AppT (getType n ns) (VarT n1)
+
+
+
+expand :: Name -> [Name] -> Q Type
+expand n0 ns = fmap simplify $ applic [] (getType n0 ns) where
+  applic :: [(Type,[Type])] -> Type -> Q Type
+  applic nts t0 = do
+    b <- t0 `contains` n0
+    if not b then return t0 else case flat t0 of
+      (TupleT _,ts) -> fmap toTuple $ mapM (applic nts) ts
+      (ConT n, ts)  ->
+        if (ConT n,ts) `elem` nts then return (ConT n0) else do
+          let rec = applic $ (ConT n,ts) : nts
+          i <- reify n
+          let fs = toTuple $ nub $ iTypes i
+          rec $ subst (zip (iParams i) ts) fs
+
+    where
+            subst nmap t1 = case t1 of
+              AppT t2 t3  -> AppT (subst nmap t2) (subst nmap t3)
+              VarT n1	-> fromMaybe t1 $ lookup n1 nmap
+              _		-> t1
+  simplify :: Type -> Type
+  simplify = toTuple . filter filt . nub . toList
+
+  filt t = case t of
+   ConT n -> n0/=n
+   AppT t1 t2 -> filt t1 && filt t2
+   _ -> True
+
+toList :: Type -> [Type]
+toList t = toList' $ flat t where
+  toList' :: (Type,[Type]) -> [Type]
+  toList' (TupleT _,ts) = concatMap toList ts
+  toList' _ = [t]
+
+toTuple :: [Type] -> Type
+toTuple [t] = t
+toTuple ts = toTuple' ts where
+  toTuple' []      = TupleT (length ts)
+  toTuple' (t:ts') = AppT (toTuple' ts') t
+  
+reTuple :: Type -> Type
+reTuple = reTuple' . toList where
+  reTuple' [] = TupleT 0
+  reTuple' [t] = t
+  reTuple' (t:ts) = AppT (AppT (TupleT 2) t) $ reTuple' ts
+
+
+iName :: Info -> Name
+iName i = case i of 
+  TyConI d -> dName d
+iTypes :: Info -> [Type]
+iTypes i = case i of 
+  TyConI d -> dTypes d
+  PrimTyConI n _ _ -> [ConT n]
+  _ -> error (show i)
+iParams :: Info -> [Name]
+iParams i = case i of 
+  TyConI d -> dParams d
+  
+
+dName d = case d of
+  DataD _ n _ _ _ -> n
+dTypes d = case d of
+  DataD _ _ _ cs _ ->  concatMap cFields cs
+  NewtypeD _ _ _ c _ -> cFields c
+  TySynD _ _ t    -> [t]
+dParams :: Dec -> [Name]
+dParams d = case d of
+  DataD _ _ ns _ _ -> map unVarBndr ns
+  NewtypeD _ _ ns _ _ -> map unVarBndr ns
+dConsts :: Dec -> [Con]
+dConsts d = case d of
+  DataD _ _ _ cs _ -> cs
+  NewtypeD _ _ _ c _ -> [c]
+
+cName :: Con -> Name
+cName c = case c of 
+  NormalC n sts     	-> n
+  RecC n _ 		-> n	
+  InfixC _ n _ 		-> n	
+  ForallC _ _ c1 	-> cName c1
+cId = conE . cName
+cFields :: Con -> [Type]
+cFields c = case c of 
+  NormalC n sts		-> map snd sts
+  InfixC st n st' 	-> [snd st,snd st']
+
+
+
+
+data T1 = T1
+
+
+dump :: Ppr a => a -> String
+dump = show . ppr
+
+
+type Collecting b a = StateT (Set.Set b) Q a
+collected :: (Ord b) => b -> Collecting b Bool
+collected = gets . Set.member
+
+collect :: (Ord b) => b -> Collecting b ()
+collect b = modify (Set.insert b)
+
+getCollected :: Collecting b a -> Q (Set.Set b)
+getCollected = flip execStateT Set.empty
+
+collectIf :: Ord b => b -> Collecting b () -> Collecting b ()
+collectIf b x = do
+  collected_b <- collected b
+  unless collected_b $ collect b >> x
+
+
+
+-- TH 2.4 compatability
+-- #if __GLASGOW_HASKELL__ >= 611
+#if MIN_VERSION_template_haskell(2,4,0)
+unVarBndr :: TyVarBndr -> Name
+unVarBndr (PlainTV n) = n
+unVarBndr (KindedTV n _) = n
+
+varBndr :: Name -> TyVarBndr
+varBndr n = (PlainTV n)
+
+allInClass :: Name -> [Type] -> [Pred]
+allInClass n vs = map (ClassP n) (map (:[]) vs)
+
+#else
+unVarBndr = id
+varBndr = id
+allInClass n vs = map (AppT (ConT n)) vs 
+#endif
+
+
+
+
+
+-- DEBUG
+topApp :: Name -> Q [Dec]
+topApp n = do
+  i@(TyConI (DataD _ _ ns _ _))  <-  reify n
+  nns1 <- replicateM (length ns) (newName "b")
+  expand n nns1 >>= error . dump
+testDimVal :: Name -> Q [Dec]
+testDimVal n = return []
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.