我采用了以下树生成器:
genTree0 :: MonadGen m => m (Tree String)
genTree0 =
Gen.recursive Gen.choice
[ Node "X" [] ]
[ Node "X" <$> Gen.list (Range.linear 0 20) genTree0 ]
并将其重写为有状态的:
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))
但是虽然我之前可以写,例如
Gen.sample genTree >= putStrLn . drawTree
我不能再用有状态的版本做到这一点,因为我肯定没有初始化状态:
> Gen.sample genTree
<interactive>:149:12: error:
• No instance for (MonadState Int Identity)
arising from a use of ‘genTree’
试图解决这个问题(假设但不完全相信GenT
并StateT
通勤),
> Gen.sample (evalStateT genTree 0)
<interactive>:5:23: error:
• Could not deduce (MonadGen
(StateT Int (Hedgehog.Internal.Gen.GenT Identity)))
我认为有一个非常小的最后一部分与类型族有关,我不明白。那会是什么?例如,如果我添加
genTree1 :: ( MonadGen m
, MonadState Int m
, GenBase m ~ Identity)
=> m (Tree String)
(只是因为我以前见过这个)
我得到另一个错误,
> Gen.sample (runStateT genTree 0)
<interactive>:15:23: error:
• Couldn't match type ‘GenBase (StateT Int (GenT Identity))’
with ‘Identity’
不幸的是,在这一点上,我只是开始猜错要应用哪个约束。
更新:另一方面,我尝试构建一个特定的 monad 转换器堆栈,因为genTree0
并且genTree1
具有相当普遍的签名:
newtype StateGen s a = StateGen { runStateGen :: StateT s (GenT IO) a }
deriving ( Functor, Applicative, Monad
, MonadState s
, MonadGen
, MonadIO
)
但这也有点错误。至少MonadGen
。
我必须在这里输入什么才能开始,更好的是,我在哪里可以学习比猜测更好的方法?