StateT在Control.Monad.Trans.State.Lazy中
内部的功能和m更高的类型使得它很难实现。
{-# LANGUAGE FlexibleContexts #-}
import Test.QuickCheck
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
instance (CoArbitrary s, Arbitrary s, Arbitrary a) =>
Arbitrary (StateT s (Maybe) a) where -- doesn't quite work
arbitrary = undefined我之所以要这样做,是因为我想使用QuickCheck检查我编写的StateT的应用实例是否正确(用于实践)。
编辑:好的,下面是我要测试的实例(据说是不正确的)
instance (Monad m) => Applicative (StateT s m) where
pure x = StateT (\s -> (\a -> (a, s)) <$> pure x)
StateT smfs <*> StateT smas = StateT $ \s -> liftA2 (\ (f, s) (a, _) -> (f a, s)) (smfs s) (smas s)发布于 2017-04-14 15:54:34
你的问题真的很有趣。实际上,使用QuickCheck来验证函子/apllicative/ monad律对于StateT单端转换器来说是非常好的。因为这是QuickCheck最有用的应用之一。
但是为Arbitrary编写StateT实例并不容易。这是可能的。但实际上是没有利润的。您应该以某种聪明的方式使用CoArbitrary类型类。还有几个扩展。这个想法在这篇博客文章中得到了描述。拥有CoArbitrary实例用于a -> b,您可以轻松地为StateT创建Arbitrary实例。
instance ( CoArbitrary s
, Arbitrary s
, Arbitrary a
, Arbitrary (m a)
, Monad m
) => Arbitrary (StateT s m a)
where
arbitrary = StateT <$> promote (\s -> fmap (,s) <$> arbitrary)然后,您可以生成状态:
ghci> (`runStateT` 3) <$> generate (arbitrary @(StateT Int Maybe Bool))
Just (True,3)您甚至可以编写属性:
propStateFunctorId :: forall m s a .
( Arbitrary s
, Eq (m (a, s))
, Show s
, Show (m (a, s))
, Functor m
)
=> StateT s m a -> Property
propStateFunctorId st = forAll arbitrary $ \s ->
runStateT (fmap id st) s === runStateT st s但是您不能运行这个属性,因为它需要instance Show作为StateT,并且不能为它编写合理的实例:(这正是QuickCheck的工作方式。它应该打印失败的反例。如果你不知道哪一次考试失败了,那么100次考试通过,1次考试失败这一事实并不能真正帮助你。这不是编程竞赛:)
ghci> quickCheck (propStateFunctorId @Maybe @Int @Bool)
<interactive>:68:1: error:
• No instance for (Show (StateT Int Maybe Bool))
arising from a use of ‘quickCheck’因此,与其生成任意的StateT,不如生成s和a,然后检查属性。
prop_StateTFunctorId :: forall s a .
( Arbitrary s
, Arbitrary a
, Eq a
, Eq s
)
=> s -> a -> Bool
prop_StateTFunctorId s a = let st = pure a
in runStateT @_ @Maybe (fmap id st) s == runStateT st s
ghci> quickCheck (prop_StateTFunctorId @Int @Bool)
+++ OK, passed 100 tests.这种方法不需要掌握一些高水平的技能。
https://stackoverflow.com/questions/43409610
复制相似问题