使用具体类型生成任意“JointList”

时间:2016-02-04 20:32:59

标签: haskell quickcheck

我正在为this course homework的一个练习编写测试。

在这个作业中定义了以下数据类型:

data JoinList m a = Empty
              | Single m a
              | Append m (JoinList m a) (JoinList m a)
              deriving (Eq, Show)

为了执行测试,我想使用JointList生成随机QuickCheck元素,m是一个Monoid,其中包含有关列表中的元素数量。这是,我想将arbitrary定义如下:

instance (Sized m0, Monoid m0, Arbitrary a0) => 
    (Arbitrary (JoinList m0 a0)) where
  arbitrary = oneof [ return Empty
                    , liftM (Single (Size 1)) arbitrary
                    , liftM2 (doAppend) arbitrary arbitrary
                    ]
              where doAppend jxs jys = Append (tag jxs <> tag jys) jxs jys

其中<>被定义为两个操作数的大小之和,Sized类定义如下:

newtype Size = Size Int
    deriving (Eq, Ord, Show, Num)

class Sized a where
  size :: a -> Size

但是,这会导致以下编译器错误:

Couldn't match expected type ‘m0’ with actual type ‘Size’
  ‘m0’ is a rigid type variable bound by
       the instance declaration at test/Spec.hs:35:10
Relevant bindings include
  arbitrary :: Gen (JoinList m0 a0) (bound at test/Spec.hs:36:3)
In the first argument of ‘Single’, namely ‘(Size 1)’
In the first argument of ‘liftM’, namely ‘(Single (Size 1))’

有没有办法实现这个目标?

1 个答案:

答案 0 :(得分:2)

我怀疑,不是支持生成由用户选择的Sized实例注释的随机列表,而是真的只是为了支持生成由特定类型Size注释的随机列表。您可以通过这种方式修改Arbitrary实例声明:

instance (m ~ Size, Arbitrary a) => Arbitrary (JoinList m a) where
    -- as before

您需要为Monoid声明明显的Size实例:

instance Monoid Size where
    mempty  = 0
    mappend = (+)

您可以完全跳过声明Sized课程。

或者,如果您确实打算生成由用户选择的实例注释的随机列表,那么您需要Sized类来提供生成注释的方法,而不是消耗它们正如班级目前提供的那样。因此,例如:

class Sized a where size :: Int -> a
instance Sized Size where size = Size

然后Arbitrary实例声明将保持不变,但会在Size的制作中将size替换为Single