我有像这样的GADT:
data TType a where
TInt :: TType Int
TBool :: TType Bool
Run Code Online (Sandbox Code Playgroud)
我想要一个像这样的功能:
genTType :: Gen (TType a)
Run Code Online (Sandbox Code Playgroud)
哪个可以生成TType类型的随机构造函数.我可以通过创建存在的合格数据类型来实现这一点
data AnyType = forall a . MkAnyType (TType a)
Run Code Online (Sandbox Code Playgroud)
然后生成随机数0到1(包括)并AnyType根据整数值创建.像这样:
intToAnyType :: Int -> AnyType
intToAnyType 0 = MkAnyType TInt
intToAnyType 1 = MkAnyType TBool
intToAnyType _ = error "Impossible happened"
Run Code Online (Sandbox Code Playgroud)
但这种方法对我来说有几个缺点:
TType数据类型添加另一个构造函数,我可能忘记修复测试,编译器不会警告我这一点.intToAnyType 1 = MkAnyType TInt.error.Int类型太宽泛了我.让这种模式匹配详尽无遗是件好事.我可以在Haskell中做些什么来消除尽可能多的缺点?最好使用此模块的发电机:
haskell type-safety gadt property-based-testing haskell-hedgehog
假设,我想在Haskell Sum的hedgehog库的帮助下测试以下的associativity属性:
a <> (b <> c) ? (a <> b) <> c
Run Code Online (Sandbox Code Playgroud)
我实际上有两种方法来生成随机输入.
Gen(使用Gen'Applicative和Monad实例)genTriple :: Get (Int, Int, Int)
genTriple = liftA3 (,,) Gen.enumBounded Gen.enumBounded Gen.enumBounded
prop_assoc :: Property
prop_assoc = property $ do
(a, b, c) <- forAll genTriple
(Sum a <> Sum b) <> Sum c === Sum a <> (Sum b <> Sum c)
Run Code Online (Sandbox Code Playgroud)
forAllprop_assoc :: Property
prop_assoc = property $ do
a <- forAll Gen.enumBounded …Run Code Online (Sandbox Code Playgroud) testing automated-tests haskell property-based-testing haskell-hedgehog
为什么没有QuickCheck类似于hedgehog's的函数success?我特别想知道如何翻译如下属性:
prop_specialPair :: Property
prop_specialPair = property $ do
(_, xs) <- forAll specialPair
case xs of
x:_ -> x /== 3
_ -> success
Run Code Online (Sandbox Code Playgroud)
在QuickCheck如果我使用=/=,然后我被迫返回类型的东西Property,而且似乎有没有固定函数返回一个通过性。
所以我要么不得不求助于Bool类型:
prop_specialPair :: SpecialPair -> Bool
prop_specialPair SpecialPair { xs } =
case xs of
x:_ -> x == 3
_ -> True
Run Code Online (Sandbox Code Playgroud)
或者对 使用非常尴尬的编码success,例如:
prop_specialPair :: SpecialPair -> Property
prop_specialPair SpecialPair { xs } =
case xs …Run Code Online (Sandbox Code Playgroud) 我面临着为一个生成器编写一个收缩函数的问题,该函数取决于另一个生成器输出的值。基本上是以下形式的生成器:
do
a <- genA
b <- f a
pure $! g a b
Run Code Online (Sandbox Code Playgroud)
在哪里genA :: Gen a,f :: a -> Gen b g :: a -> b -> c。为了论证的方便,假设g = (,). 那么问题是,给定一对(a, b),收缩可能会破坏,和a之间存在的关系。afb
举个例子,请考虑以下具有缓存长度的列表:
data List =
List
{ llength :: Int
, list :: [Int]
} deriving (Eq, Show)
Run Code Online (Sandbox Code Playgroud)
该arbitrary函数可以很容易地定义:
instance Arbitrary List where
arbitrary = do
n <- choose (0, 10)
xs …Run Code Online (Sandbox Code Playgroud) 我制作了一个 Hedgehog 生成器,可以通过以下方式生成任意 256 位值:
genWord256 :: Gen Word256
genWord256 = do
bytes <- Gen.integral (Range.linear 0 31)
let lo = 2 ^ (8 * bytes)
hi = 2 ^ (8 * (bytes + 1))
pred <$> Gen.integral (Range.constant lo hi)
Run Code Online (Sandbox Code Playgroud)
让 size 参数决定数字中的字节数,我认为对我的应用程序很有意义。但是,评估此生成器如何缩小并应用于ceiling . logBase 2此,我的问题是:
为什么刺猬决定强调其初始结果的附近?我是否以某种方式误解了“不受大小参数影响的范围”的含义?( Range.constant) 我会认为这里的任何收缩都必须具有较少的位数。
?> Gen.print genWord256
=== Outcome ===
68126922926972638
=== Shrinks ===
112 -- 7 bits
4035711763 -- 32 bits
106639875637011 -- 47 bits
281474976710655 …Run Code Online (Sandbox Code Playgroud)