I would like to generate Arbitrary value for ordered tree-like structure whose type is, say
data Tree a = Leaf | Node (Tree a) a (Tree a)
A function that inserts value into this tree while keeping it ordered would require that value should be Ord. But to generate ordered Trees for Arbitrary instance I would need to generate value in range "[low,hi]" and Ord is insufficient for that. So I also required that value is Enum since Enum allows getting values from given boundary. The choose below also requires System.Random.Random:
import Test.QuickCheck.Arbitrary
import System.Random
generateTree :: (Arbitrary a, Ord a, Enum a, Random a) => a -> a -> Gen (Tree a)
generateTree l u = do
genLeaf <- arbitrary
if genLeaf
then return Leaf
else do
x <- choose (l, u)
left <- generateTree l (pred x)
right <- generateTree (succ x) u
return $ Node left x right
So to use this for arbitrary implementation I should require the same classes in Arbitrary class:
instance (Arbitrary a, Ord a, Enum a, Rand.Random a) => Arbitrary (Tree a) where
arbitrary = do
l <- arbitrary
u <- arbitrary
generateTree l u
Here, while requirement Ord a => Tree a is enough for data structure itself, I require (Arbitrary a, Ord a, Enum a, Rand.Random a) => Tree a for it's generator. It looks like leaking implementation details into declaration - probably I look at this wrong way, I am learning Haskell. But still there are questions:
- Is there a way to declare more generic generator that does not have as much requirements?
- Is there a way to declare other instance for
Arbitrary (Tree a)along with one above that would have different set of requirements, something likeArbitrary (Tree Int)that would be used forInts only?
Aucun commentaire:
Enregistrer un commentaire