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?