运行有状态的刺猬发电机

时间:2019-09-27 06:01:08

标签: haskell haskell-hedgehog

我使用了以下树生成器:

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变压器堆栈,因为genTree0genTree1具有非常通用的签名:

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

但是这也有点错误。至少MonadGen

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

0 个答案:

没有答案