【发布时间】:2018-10-03 12:57:03
【问题描述】:
使用 QuickCheck,可以编写参数化多态属性,如下所示:
associativityLaw :: (Eq a, Show a, Semigroup a) => a -> a -> a -> Property
associativityLaw x y z = (x <> y) <> z === x <> (y <> z)
这只是一个例子,因为我的实际属性更复杂,但它很好地说明了问题。此属性验证对于 a 类型,<> 运算符是关联的。
想象一下,我想为不止一种类型使用此属性。我可以这样定义我的测试列表:
tests =
[
testGroup "Monoid laws" [
testProperty "Associativity law, [Int]" (associativityLaw :: [Int] -> [Int] -> [Int] -> Property),
testProperty "Associativity law, Sum Int" (associativityLaw :: Sum Int -> Sum Int -> Sum Int -> Property)
]
]
这可行,但感觉不必要地冗长。我希望能够简单地说明对于给定的属性,a 应该是 [Int],或者 a 应该是 Sum Int。
类似这样的假设语法:
testProperty "Associativity law, [Int]" (associativityLaw :: a = [Int]),
testProperty "Associativity law, Sum Int" (associativityLaw :: a = Sum Int)
有没有办法做到这一点,也许使用 GHC 语言扩展?
我的实际问题涉及更高种类的类型,我希望能够说明这一点,例如f a 是[Int],或者f a 是Maybe String。
我知道this answer,但至少如其中所述,这两个选项(Proxy 和Tagged)似乎都太尴尬而无法真正解决问题。
【问题讨论】:
-
我想我宁愿明确指定生成器而不是默认任意类型。我用here 的例子做了一个要点。当然,它在 Hedgehog 中,但可以移植到 QC。 /cc @dcastro