Use HSpec and QuickCheck to verify Data.Monoid properties

非 Y 不嫁゛ 提交于 2019-12-04 09:21:55

Notice the type of property :: Testable prop => prop -> Property. The type var prop is erased, and instance resolution can't take place if the type variable is no longer available. Basically what you want to do is defer instace selection, and to do that you must make the type available until the moment you pick the instance.

One way is to carry around an extra Proxy prop parameter:

-- Possibly Uuseful helper function
propertyP :: Testable prop => Proxy prop -> prop -> Property 
propertyP _ = property 

monoidProp :: forall m . (Arbitrary m, Testable m, Show m, Monoid m, Eq m) 
           => Proxy m -> Property 
monoidProp _ = property (prop_Monoid_mappend_mempty_x :: m -> Property)

monoidSpec :: (Monoid m, Arbitrary m, Testable m, Show m, Eq m) => Proxy m -> Spec
monoidSpec x = it "mappend mempty x = x" $ monoidProp x 

main0 :: IO ()
main0 = hspec $ do
    describe "Data.Monoid.Sum" $ do
        monoidSpec (Proxy :: Proxy (Sum Int))
    describe "Data.Monoid.Product" $ do
        monoidSpec (Proxy :: Proxy (Product Double))

Another way is to use a library like tagged which provides the type Tagged, which simply adds some phantom type parameter to an existing type:

import Data.Tagged

type TaggedProp a = Tagged a Property 
type TaggedSpec a = Tagged a Spec 

monoidPropT :: forall a. (Monoid a, Arbitrary a, Show a, Eq a) 
            => TaggedProp a
monoidPropT = Tagged (property (prop_Monoid_mappend_mempty_x :: a -> Property))

monoidSpecT :: forall a . (Monoid a, Arbitrary a, Show a, Eq a) => TaggedSpec a
monoidSpecT = Tagged $ it "mappend mempty x = x" 
                          (unTagged (monoidPropT :: TaggedProp a))

main1 :: IO ()
main1 = hspec $ do
    describe "Data.Monoid.Sum" $ do
        untag (monoidSpecT :: TaggedSpec (Sum Int))
    describe "Data.Monoid.Product" $ do
        untag (monoidSpecT :: TaggedSpec (Product Double))

These solutions are essentially equivalent, although in some cases one or the other may be much more convenient. Since I don't know enough about your use case, I've included both.

Both of these require only -XScopedTypeVariables.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!