我想使用HSpec和QuickCheck来验证单子的属性(结合律和单位元素)。我将验证特定实例,但希望保持大部分代码是多态的。在经过几个小时的努力后,我得出了以下结论:
module Test where
import Test.Hspec
import Test.QuickCheck
import Data.Monoid
instance (Arbitrary a) => Arbitrary (Sum a) where
arbitrary = fmap Sum arbitrary
instance (Arbitrary a) => Arbitrary (Product a) where
arbitrary = fmap Product arbitrary
prop_Monoid_mappend_mempty_x x = mappend mempty x === x
sumMonoidSpec = it "mappend mempty x = x" $ property (prop_Monoid_mappend_mempty_x :: Sum Int -> Property)
productMonoidSpec = it "mappend mempty x = x" $ property (prop_Monoid_mappend_mempty_x :: Product Double -> Property)
main :: IO ()
main = hspec $ do
describe "Data.Monoid.Sum" $ do
sumMonoidSpec
describe "Data.Monoid.Product" $ do
productMonoidSpec
我希望你能够实现多态性,尽管这并不是必需的。
monoidSpec = it "mappend mempty x = x" $ property prop_Monoid_mappend_mempty_x
您可以稍后指定实际的 Monoid 实例 (Sum、Product) 和类型 (Int、Double)。问题在于它无法通过类型检查。我一直得到以下错误:
src/Test.hs@18:42-18:50 No instance for (Arbitrary a0) arising from a use of property
The type variable a0 is ambiguous
Note: there are several potential instances:
instance Arbitrary a => Arbitrary (Product a)
-- Defined at /home/app/isolation-runner-work/projects/68426/session.207/src/src/Test.hs:10:10
instance Arbitrary a => Arbitrary (Sum a)
-- Defined at /home/app/isolation-runner-work/projects/68426/session.207/src/src/Test.hs:7:10
instance Arbitrary () -- Defined in Test.QuickCheck.Arbitrary
...plus 27 others …
src/Test.hs@18:51-18:79 No instance for (Monoid a0)
arising from a use of prop_Monoid_mappend_mempty_x
The type variable a0 is ambiguous
Note: there are several potential instances:
instance Monoid () -- Defined in Data.Monoid
instance (Monoid a, Monoid b) => Monoid (a, b)
-- Defined in Data.Monoid
instance (Monoid a, Monoid b, Monoid c) => Monoid (a, b, c)
-- Defined in Data.Monoid
...plus 18 others …
我知道我需要将Monoid约束在多态版本中为Arbitrary、Eq和Show,但我不知道如何实现。
问题是如何以多态方式表达Monoid的规范并避免代码重复?