使用 Hedgehog(或任何其他基于属性的测试框架)生成随机 GADT 的最安全方法
Posted
技术标签:
【中文标题】使用 Hedgehog(或任何其他基于属性的测试框架)生成随机 GADT 的最安全方法【英文标题】:Safest way to generate random GADT with Hedgehog (or any other property-based testing framework) 【发布时间】:2018-06-22 20:06:46 【问题描述】:我有这样的 GADT:
data TType a where
TInt :: TType Int
TBool :: TType Bool
我想要一个这样的功能:
genTType :: Gen (TType a)
可以生成TType
类型的随机构造函数。我可以简单地通过创建存在限定的数据类型来做到这一点,例如
data AnyType = forall a . MkAnyType (TType a)
然后生成从0
到1
(包括)的随机数,并根据整数值创建AnyType
。像这样:
intToAnyType :: Int -> AnyType
intToAnyType 0 = MkAnyType TInt
intToAnyType 1 = MkAnyType TBool
intToAnyType _ = error "Impossible happened"
但这种方法对我来说有几个缺点:
-
没有外部类型安全。如果我向
TType
数据类型添加另一个构造函数,我可能会忘记修复测试,编译器不会就此发出警告。
编译器无法阻止我写intToAnyType 1 = MkAnyType TInt
。
我不喜欢这个error
。 Int
类型对我来说太宽泛了。让这种模式匹配详尽无遗会很好。
我可以在 Haskell 中做些什么来尽可能地消除这里的缺点?最好使用此模块中的生成器:
https://hackage.haskell.org/package/hedgehog-0.5.1/docs/Hedgehog-Gen.html【问题讨论】:
类型检查器无法帮助您处理第 2 点或第 3 点。编译器无法阻止您编写intToAnyType 1 = MkAnyType TInt
,因为类型系统不够强大,无法表达输出构造函数必须以某种方式对应于输入整数;这需要依赖类型。出于同样的原因,您也不能避免使用部分函数(您当然可以返回Maybe AnyType
)。对于#1,你可以使用tagToEnum#
(假设你的类型确实是一个枚举)
@user2407038 类型系统不够强大。但我相信经过测试的库 :) 例如,如果我能自动为我的 GADT 派生 Enum
和 Bounded
,我可以使用来自 Hedgehog 的 enumBounded
生成器:hackage.haskell.org/package/hedgehog-0.5.1/docs/… 所以,尽可能多地委派工作到经过测试的生成库对我来说是一个很好的解决方案。
【参考方案1】:
使用 Template Haskell 生成 genTType
可能是自动维护生成器的最佳选择,因为没有对 GADT 的通用编程支持。
最后一点,不要生成一个整数然后将其映射到一个值,而是使用oneof
或element
。
element [MkAnyType TInt, MkAnyType TBool]
【讨论】:
感谢element
组合器!这会有所帮助。以上是关于使用 Hedgehog(或任何其他基于属性的测试框架)生成随机 GADT 的最安全方法的主要内容,如果未能解决你的问题,请参考以下文章
基于 JAXL 的聊天客户端。需要帮助连接到 Gtalk 或其他服务器以进行测试
CodeForces615B-Longtail Hedgehog-dp/图