自定义列表类型

时间:2017-08-09 13:55:05

标签: haskell

我有以下数据类型(如列表):

  data List a =
      Nil
    | Cons a (List a)
    deriving (Eq, Show)

并为Monoid创建了一个实例:

  instance Monoid (List a) where
    mempty = Nil
    mappend Nil ys = ys
    mappend (Cons x xs) ys = Cons x (mappend xs ys) 

我尝试为Arbitrary编写一个实例来测试后者,但无法完成它:

  instance Arbitrary a => Arbitrary (List a) where
    arbitrary = do  

请帮我完成这项功能。

3 个答案:

答案 0 :(得分:2)

我们将其分为两个功能。首先,我们生成一个固定长度列表的函数:

vectorList :: (Arbitrary a) => Int -> Gen (List a)
vectorList n = if n <= 0 
                 then return Nil
                 else Cons <$> arbitrary <*> vectorList (n - 1)

现在我们可以生成固定大小的仲裁列表,我们可以使用sized生成列表:

instance Arbitrary a => Arbitrary (List a) where
  arbitrary = sized vectorList

这确保我们启用QuickCheck来选择列表的大小。通常,QuickCheck会在测试中首先选择小尺寸参数并增加尺寸。如果您要选择随机大小,您可能会创建一个非常长的列表,其中一个小列表已足以检查您的测试用例。

请注意,vectorList只适用于您的数据类型replicateM n arbitrary。如果您提供fromList :: [a] -> List a,则可以将vectorList更改为

vectorList n = fromList (replicateM n arbitrary)

但是你可以使用

instance Arbitrary a => Arbitrary (List a) where
  arbitrary = fmap fromList arbitrary

答案 1 :(得分:1)

这个怎么样?

replicateM 0 action = Nil
replicateM n action = Cons <$> action <*> replicateM (n-1) action

instance Arbitrary a => Arbitrary [a] where
    arbitrary = do
        length <- getSize
        replicateM length arbitrary

replicateM版本与the standard version类似,不同之处在于它返回List而不是[]

答案 2 :(得分:1)

使用oneof函数怎么样?

instance Arbitrary a => Arbitrary (List a) where
  arbitrary = oneof [pure Nil, Cons <$> arbitrary <*> arbitrary]

它将生成空值Nil或非空列表。 oneof获取Gen a值列表,这就是pure<$>需要<*>将值包装到Gen所需的原因。 <{1}}和return也可以使用。

在定义liftM2之后快速检查一个简单的测试:

instance

顺便说一下,在大多数情况下prop_nil_mappend :: List Int -> Bool prop_nil_mappend xs = mappend Nil xs == xs main :: IO () main = quickCheck prop_nil_mappend 没有非空列表那么有用,所以你可以定义每个列表的生成频率:

Nil
相关问题