Running a stateful Hedgehog generator

177 Views Asked by At

I've taken the following tree generator:

genTree0 :: MonadGen m => m (Tree String)
genTree0 =
  Gen.recursive Gen.choice
    [ Node "X" [] ]
    [ Node "X" <$> Gen.list (Range.linear 0 20) genTree0 ]

and rewritten it into a stateful one:

genTree1 :: (MonadGen m, MonadState Int m) => m (Tree String)
genTree1 =
  Gen.recursive Gen.choice
    [ (`Node` []) <$> next ]
    [ Node <$> next <*> Gen.list (Range.linear 0 20) genTree1 ]
  where
    next :: MonadState Int m => m String
    next = fmap show (get <* modify (+1))

But whereas I could before write e.g.

Gen.sample genTree >= putStrLn . drawTree

I can no longer do that with the stateful version, because surely I have not initialized the state:

> Gen.sample genTree

<interactive>:149:12: error:
    • No instance for (MonadState Int Identity)
        arising from a use of ‘genTree’

Trying to fix this (assuming but not being fully convinced that GenT and StateT commute),

> Gen.sample (evalStateT genTree 0)

<interactive>:5:23: error:
    • Could not deduce (MonadGen
                          (StateT Int (Hedgehog.Internal.Gen.GenT Identity)))

I think there's a very small, last part related to type families that I'm not grokking. What could that be? If, for example, I add

genTree1 :: ( MonadGen m
            , MonadState Int m
            , GenBase m ~ Identity)
         => m (Tree String)

(simply because I've seen this before)

I get another error instead,

> Gen.sample (runStateT genTree 0)

<interactive>:15:23: error:
    • Couldn't match type ‘GenBase (StateT Int (GenT Identity))’
                     with ‘Identity’

Unfortunately, at this point, I just start guessing wrong at which constraint to apply.

Update: In another vein, I've tried to construct a specific monad transformer stack, since genTree0 and genTree1 have quite general signatures:

newtype StateGen s a = StateGen { runStateGen :: StateT s (GenT IO) a }
  deriving ( Functor, Applicative, Monad
           , MonadState s
           , MonadGen
           , MonadIO
           )

but this is also slightly wrong wrt. at least MonadGen.

What must I type here, to get going, and better yet, where can I learn a better way than guessing?

0

There are 0 best solutions below