The current Arbitrary
instance used to test Data.Set
is too complicated for my taste. I don't really understand it, so I don't really trust it. I came up with the idea of separating the shape generation from the value generation.
Using
class Monad m => MonadGen m where
liftGen :: Gen a -> m a
instance MonadGen Gen where
liftGen = id
instance MonadGen m => MonadGen (StateT s m) where
liftGen = lift . liftGen
I can write
mkArb :: MonadGen m => m a -> Int -> m (Set a)
mkArb step n
| n <= 0 = pure Tip
| n == 1 = singleton <$> step
| n == 2 = do
dir <- liftGen arbitrary
p <- step
q <- step
if dir
then pure (Bin 2 q (singleton p) Tip)
else pure (Bin 2 p Tip (singleton q))
| otherwise = do
let upper = (3*(n - 1)) `quot` 4
let lower = (n + 2) `quot` 4
ln <- liftGen $ choose (lower, upper)
let rn = n - ln - 1
(\lt x rt -> Bin n x lt rt) <$> mkArb step ln <*> step <*> mkArb step rn
Then I can use something like StateT s Gen
to populate the set with strictly increasing elements.
I have two questions:
Do I successfully generate all balanced tree shapes? How can I check?
What would be a good way to fill in values? I want sets with dense areas and with sparse areas. When I generate two sets I want them to overlap some times but not others, and their ranges to overlap some times but not others. I don't really have a good sense of how to accomplish these goals.