3

我采用了以下树生成器:

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’

试图解决这个问题(假设但不完全相信GenTStateT通勤),

> 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

我必须在这里输入什么才能开始,更好的是,我在哪里可以学习比猜测更好的方法?

4

0 回答 0