创建一个有条件的任意实例(*由于使用“quickCheck”而产生的不明确类型变量“a”)
Creating a conditioned Arbitrary instance ( * Ambiguous type variable `a' arising from a use of `quickCheck')
我想做这个测试:
prop_inverse_stringsToInts st = isDigitList st ==> st == map show (stringsToInts st)
它正在测试一个将字符串列表转换为整数列表的函数,但当然字符串需要是数字,所以我创建了一个先决条件来使用我创建的 isDigitList 函数进行检查,但是条件太具体,quickCheck 放弃:“*** 放弃!仅通过 43 项测试;1000 项测试被丢弃。”
所以我想为我的案例创建一个 Arbitrary 实例,但问题是我没有使用 Arbitrary 的经验,所以我真的不知道该怎么做,每次我打乱代码时我都会收到一个新错误。我想要的只是一个 Arbitrary,只有 returns Foo [String] 如果它通过 isDigitList(它接收一个 [String] 和 returns 一个 Bool)。到目前为止,我有这样的东西:
Foo a = Foo [String] deriving (Show,Eq)
instance (Arbitrary a) => Arbitrary (Foo a ) where
arbitrary = do
st <- (arbitrary :: Gen [String])
if isDigitList st
then do return (Foo st)
else do return (Foo []) -- This is probably a bad idea
我将 属性 更改为:
prop_inverse_stringsToInts :: Foo a -> Bool
prop_inverse_stringsToInts (Foo st) = st == map show (stringsToInts st)
但现在我收到错误“* Ambiguous type variable a0' arising from a use of `quickCheck'”,即使我是这样 运行 quickCheck : > quickCheck (prop_inverse_stringsToInts : : Foo a -> Bool)
有人可以帮忙吗?提前致谢!
看来您了解基础知识,但为了确保万无一失,我会在这里重复一遍。有两种方法可以让 QuickCheck 生成您想要的输入:
让它生成一些输入,然后过滤掉不需要的,或者
让它只生成您想要的输入。
您从选项 1 开始,但如您所见,结果并不理想。与 String
的所有可能列表相比,数字列表确实没有那么多。更好的选择是只生成你想要的输入。
要在选项 2 上取得成功,您需要制作一个 生成器 ,它是一个 Gen [String]
类型的值,它生成 String
的列表符合您的标准。您建议的生成器仍然使用过滤的方法,因此您可能想尝试不同的方法。相反,请考虑以下内容:
genDigitStrings :: Gen [String]
genDigitStrings = do
intList <- arbitrary :: Gen [Integer]
return $ fmap show intList
此生成器生成任意 String
列表,这些列表始终显示为整数,这意味着它们将始终是数字列表。如果需要,您可以继续将其插入到某个新类型的 Arbitrary
实例中。
为了您自己的理智,您甚至可以通过这样的测试来检查您的工作:
propReallyActuallyDigitStrings = forAll genDigitStrings isDigitList
如果通过,则您有信心您的生成器实际上只生成数字列表,如果失败,则您应该调整您的生成器。
我想做这个测试:
prop_inverse_stringsToInts st = isDigitList st ==> st == map show (stringsToInts st)
它正在测试一个将字符串列表转换为整数列表的函数,但当然字符串需要是数字,所以我创建了一个先决条件来使用我创建的 isDigitList 函数进行检查,但是条件太具体,quickCheck 放弃:“*** 放弃!仅通过 43 项测试;1000 项测试被丢弃。” 所以我想为我的案例创建一个 Arbitrary 实例,但问题是我没有使用 Arbitrary 的经验,所以我真的不知道该怎么做,每次我打乱代码时我都会收到一个新错误。我想要的只是一个 Arbitrary,只有 returns Foo [String] 如果它通过 isDigitList(它接收一个 [String] 和 returns 一个 Bool)。到目前为止,我有这样的东西:
Foo a = Foo [String] deriving (Show,Eq)
instance (Arbitrary a) => Arbitrary (Foo a ) where
arbitrary = do
st <- (arbitrary :: Gen [String])
if isDigitList st
then do return (Foo st)
else do return (Foo []) -- This is probably a bad idea
我将 属性 更改为:
prop_inverse_stringsToInts :: Foo a -> Bool
prop_inverse_stringsToInts (Foo st) = st == map show (stringsToInts st)
但现在我收到错误“* Ambiguous type variable a0' arising from a use of `quickCheck'”,即使我是这样 运行 quickCheck : > quickCheck (prop_inverse_stringsToInts : : Foo a -> Bool)
有人可以帮忙吗?提前致谢!
看来您了解基础知识,但为了确保万无一失,我会在这里重复一遍。有两种方法可以让 QuickCheck 生成您想要的输入:
让它生成一些输入,然后过滤掉不需要的,或者
让它只生成您想要的输入。
您从选项 1 开始,但如您所见,结果并不理想。与 String
的所有可能列表相比,数字列表确实没有那么多。更好的选择是只生成你想要的输入。
要在选项 2 上取得成功,您需要制作一个 生成器 ,它是一个 Gen [String]
类型的值,它生成 String
的列表符合您的标准。您建议的生成器仍然使用过滤的方法,因此您可能想尝试不同的方法。相反,请考虑以下内容:
genDigitStrings :: Gen [String]
genDigitStrings = do
intList <- arbitrary :: Gen [Integer]
return $ fmap show intList
此生成器生成任意 String
列表,这些列表始终显示为整数,这意味着它们将始终是数字列表。如果需要,您可以继续将其插入到某个新类型的 Arbitrary
实例中。
为了您自己的理智,您甚至可以通过这样的测试来检查您的工作:
propReallyActuallyDigitStrings = forAll genDigitStrings isDigitList
如果通过,则您有信心您的生成器实际上只生成数字列表,如果失败,则您应该调整您的生成器。