gpt4 book ai didi

haskell - 快速检查:生成任意集合的任意元素

转载 作者:行者123 更新时间:2023-12-02 17:07:59 25 4
gpt4 key购买 nike

假设我正在为 Data.Set 编写测试。我想检查从集合中删除元素是否有效,因此我可能会编写如下内容:

prop_deleteA it x = member x it ==> not (member x (delete x it))

假设it有一个合适的Arbitrary实例。然而,这依赖于快速检查生成恰好存在于集合中的x值,这通常是不能保证的。如果x可以依赖于it,从而保证x已经是it的成员,那就更好了。我该怎么做?

我想我可以写

prop_deleteB it f = let x = f it
in not (member x (delete x it))

其中f::Set a -> a通过共任意的方式适本地定义。然而,co任意只允许我们定义f::Set a -> b,不幸的是这不是我们想要的。到目前为止,我最好的想法是定义一个新类型

data SetAndElement a = SetAndElement (Set a) a

它允许我们编写合适的任意实例

instance (Ord a, Arbitrary a) => Arbitrary (SetAndElement a) where
arbitrary = do it <- suchThat arbitrary (not . Set.null)
x <- elements (elems it)
return (SetAndElement it x)

允许将 prop_delete 写为

prop_deleteC (SetAndElement it x) = not (member x (delete x it))

这可行,但似乎有点复杂;还有更好的选择吗? (如果没有,我将修改问题并将其作为答案。)实际的 Data.Set 实现(容器包)通过检查 (delete x) 来测试删除。 (insert x) == id 如果 x 还不是给定集合的成员。

最佳答案

这取决于您可用的发电机。例如,如果您已经有 setOf1 (生成一个至少包含一个元素的 Set)和 setElements (从 Set 中获取元素),可以用forAll来写:

-- example implementations of both combinators
setOf1 :: (Arbitrary a, Ord a) => Gen a -> Gen (Set a)
setOf1 = fmap fromList . listOf1

setElements :: Set a -> Gen a
setElements = elements . toList

prop_delete =
forAll (setOf1 arbitrary) $ \theSet ->
forAll (setElements theSet) $ \x ->
not (member (x :: Int) (delete x theSet))

这与SetAndElement基本相同,但我们使用的不是固定的data类型,而是可用于进一步测试的可重用函数:

prop_null =  forAll (setOf1 (arbitrary :: Gen Integer)) $ not . null

但是,即使您不编写 setOf1setElementsforAll 对于简单测试来说也相当简洁:

prop_delete :: (Arbitrary a, Ord a) => (NonEmptyList a) -> Property
prop_delete (NonEmpty xs) =
let theSet = fromList xs
in forAll (elements xs) $ \x ->
not (member x (delete x theSet))

如果您提供setElementsNonEmptySet,则可以写为

newtype NonEmptySet x = NonEmptySet {getNonEmptySet :: Set a}

instance (Ord a, Arbitray a) => Arbitrary (NonEmptySet a) where
arbitrary = fmap NonEmptySet . setOf1 $ arbitrary

prop_delete :: (Arbitrary a, Ord a) => (NonEmptySet a) -> Property
prop_delete (NonEmptySet theSet) =
forAll (setElements theSet) $ \x ->
not (member x (delete x theSet))

这样,您就可以使用 NonEmptySet 进行需要非空集的测试,而 setElements 仅用于实际需要随机选择元素的测试。

关于haskell - 快速检查:生成任意集合的任意元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35528777/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com