This module is a library of useful generators for structural types. Additional generator modules should be added to the Generator directory. \begin{code}
{-# LANGUAGE FlexibleInstances #-}

module Test.GenCheck.Generator.StructureGens 
  ( genListOf
  , genListAll
  , listStdGens
  , genTplAll
  ) where

import Test.GenCheck.Base.Base (Rank)
import Test.GenCheck.Generator.Enumeration (Label(..))
import Test.GenCheck.Generator.Generator (Generator, StandardGens(..), Testable(..))
import Test.GenCheck.Generator.BaseGens() -- Testable instances
import Test.GenCheck.Generator.Substitution (Structure(..), Structure2(..))

\end{code} Lists are a special kind of structure to generate, since there is only one possible list for each rank, and the substitution values are already in a list. The genListOf combinator turns a generator of a type a into a generator of lists of a's of the specified rank. The rank of the resulting generator defines the length of the lists of a's it generates. The basic list generator, with unit as the sort, is given as genListAll. The Structure class is provided for completeness, but there is only one possible list for any given rank. \begin{code}
genListOf :: Generator a -> Rank -> Generator [a]
genListOf g r l = let xs = g r in subLs xs
  where subLs [] = []
        subLs xs@(_:_) = let (ys',yss) = splitAt l xs in ys' : (subLs yss)

instance Structure [] where
  substitute lxs ys = lsub lxs ys
    where 
       lsub [] zs          = (Just [], zs)
       lsub (_:_) []       = (Nothing, [])
       lsub (_:xs) (z:zs)  = 
            let (mlys', ys') = lsub xs zs
                mlys = maybe Nothing (\lys -> Just (z:lys)) mlys'
            in (mlys, ys')

-- remember that generating a list of rank 1 gives the empty list, not a list of one element   
genListAll :: Generator [Label]
genListAll r = [take (r-1) (repeat A)]

listStdGens :: StandardGens [Label]
listStdGens = StdGens g g (\_ -> g) (\_ -> g) 
  where g = genListAll

instance Testable [Label] where
  stdTestGens = listStdGens

listStdSub :: (Testable a) => StandardGens [a]
listStdSub = 
  let stdg = stdTestGens
  in StdGens (vector (genAll stdg 1)) (vector (genXtrm stdg 1)) 
             (\k -> (vector (genUni stdg k 1))) (\s -> (vector (genRand stdg s 1)))
  where vector xs r = let (x, xs') = splitAt r xs in x : (vector xs' r)

instance Testable [Int] where
  stdTestGens = listStdSub :: StandardGens [Int]

\end{code} A pair generator is two sorted, so is an instance of Structure2. Pairs are always of rank 2. \begin{code}
instance Structure2 (,) where
  substitute2 _ [] ys = (Nothing, [], ys)
  substitute2 _ xs [] = (Nothing, xs, [])
  substitute2 _ (x:xs) (y:ys) = (Just (x,y), xs, ys)
  
genTplAll :: Generator (Label, Label)
genTplAll r | r == 2    = [(A,B)]
genTplAll _ | otherwise = []

tplStdGens :: StandardGens (Label, Label)
tplStdGens = StdGens g g (\_ -> g) (\_ -> g) where g = genTplAll

instance Testable (Label,Label) where
  stdTestGens = tplStdGens
\end{code}