nh2*_*nh2 14 haskell quickcheck
我有一个Haskell数据类型
data Mytype
= C1
| C2 Char
| C3 Int String
Run Code Online (Sandbox Code Playgroud)
如果我case在a Mytype并忘记处理其中一个案例,GHC会给我一个警告(详尽检查).
我现在想编写一个QuickCheck Arbitrary实例来生成MyTypes如下:
instance Arbitrary Mytype where
arbitrary = do
n <- choose (1, 3 :: Int)
case n of
1 -> C1
2 -> C2 <$> arbitrary
3 -> C3 <$> arbitrary <*> someCustomGen
Run Code Online (Sandbox Code Playgroud)
这个问题是我可以添加一个新的替代方案Mytype并忘记更新Arbitrary实例,因此让我的测试不测试该替代方案.
我想找到一种方法来使用GHC的详尽检查器来提醒我在我的任意实例中被遗忘的案例.
我想出的最好的是
arbitrary = do
x <- elements [C1, C2 undefined, C3 undefined undefined]
case x of
C1 -> C1
C2 _ -> C2 <$> arbitrary
C3 _ _ -> C3 <$> arbitrary <*> someCustomGen
Run Code Online (Sandbox Code Playgroud)
但它并不是真的很优雅.
我直觉地认为没有100%的清洁解决方案,但是会欣赏任何可以减少忘记此类情况的机会 - 尤其是在代码和测试分离的大型项目中.
这里我利用了一个未使用的变量_x。但这并不比您的解决方案更优雅。
instance Arbitrary Mytype where
arbitrary = do
let _x = case _x of C1 -> _x ; C2 _ -> _x ; C3 _ _ -> _x
n <- choose (1, 3 :: Int)
case n of
1 -> C1
2 -> C2 <$> arbitrary
3 -> C3 <$> arbitrary <*> someCustomGen
Run Code Online (Sandbox Code Playgroud)
当然,必须使最后一个case与 的虚拟定义保持一致_x,因此它不是完全 DRY。
或者,可以利用 Template Haskell 构建一个编译时断言,检查其中的构造函数是否Data.Data.dataTypeOf是预期的构造函数。该断言必须与Arbitrary实例保持一致,因此这也不完全是 DRY。
如果您不需要自定义生成器,我相信Data.Data可以Arbitrary通过 Template Haskell 来生成实例(我想我看到了一些代码正是这样做的,但我不记得在哪里)。这样,实例就不可能错过构造函数。