生成具有具体类型的任意“JointList”
Generating arbitrary `JointList` with concrete types
我正在为 this course homework 的练习之一编写测试。
在这个作业中定义了以下数据类型:
data JoinList m a = Empty
| Single m a
| Append m (JoinList m a) (JoinList m a)
deriving (Eq, Show)
为了进行测试,我想使用 QuickCheck
生成随机的 JointList
元素,这样 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
class定义如下:
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))’
有办法实现吗?
我怀疑您不是支持生成由用户选择的 Sized
实例注释的随机列表,而是真的只想支持生成由特定类型 Size
注释的随机列表。您可以通过这种方式修改 Arbitrary
实例声明:
instance (m ~ Size, Arbitrary a) => Arbitrary (JoinList m a) where
-- as before
您需要为 Size
声明明显的 Monoid
实例:
instance Monoid Size where
mempty = 0
mappend = (+)
您可以完全跳过 Sized
class 的声明。
或者,如果您确实打算生成由用户选择的实例注释的随机列表,那么您需要 Sized
class 提供一种方法来 生成 注释,而不是像 class 当前提供的那样使用它们。因此,例如:
class Sized a where size :: Int -> a
instance Sized Size where size = Size
然后 Arbitrary
实例声明将保持不变,但会在 Single
.
的生产中将 Size
替换为 size
我正在为 this course homework 的练习之一编写测试。
在这个作业中定义了以下数据类型:
data JoinList m a = Empty
| Single m a
| Append m (JoinList m a) (JoinList m a)
deriving (Eq, Show)
为了进行测试,我想使用 QuickCheck
生成随机的 JointList
元素,这样 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
class定义如下:
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))’
有办法实现吗?
我怀疑您不是支持生成由用户选择的 Sized
实例注释的随机列表,而是真的只想支持生成由特定类型 Size
注释的随机列表。您可以通过这种方式修改 Arbitrary
实例声明:
instance (m ~ Size, Arbitrary a) => Arbitrary (JoinList m a) where
-- as before
您需要为 Size
声明明显的 Monoid
实例:
instance Monoid Size where
mempty = 0
mappend = (+)
您可以完全跳过 Sized
class 的声明。
或者,如果您确实打算生成由用户选择的实例注释的随机列表,那么您需要 Sized
class 提供一种方法来 生成 注释,而不是像 class 当前提供的那样使用它们。因此,例如:
class Sized a where size :: Int -> a
instance Sized Size where size = Size
然后 Arbitrary
实例声明将保持不变,但会在 Single
.
Size
替换为 size