Reputation: 6847
I have this method to test associativity for a Semigroup
semigroupdAssoc :: (Eq m, Semigroup m) => m -> m -> m -> Bool
semigroupdAssoc a b c = a <> (b <> c) == (a <> b) <> c
Given the following type
newtype Combine a b =
Combine { unCombine :: a -> b }
My Semigroup implementation i
instance Semigroup b => Semigroup (Combine a b) where
(<>) (Combine u) (Combine u') = Combine (u <> u')
I am stuck on how should I write a quick test,
Let's say I want to test for String,
type CombineAssoc = Combine String String -> Combine String String -> Combine String String -> Bool
And the test will be
quickCheck (semigroupdAssoc :: CombineAssoc)
I know I have to write a Arbitrary
implementation for Combine
but I can't figure out how.
Figured out solution, but I don't understand it.
implementation of Arbitrary for Combine looks like this:
instance (CoArbitrary a, Arbitrary b) => Arbitrary (Combine a b) where
arbitrary = do
Combine <$> arbitrary
need to implement Show also (not really great)
instance Show (Combine a b) where
show (Combine _) = "unCombine"
Update the assoc function for this data type
combineSemigroupAssoc :: (Eq b, Semigroup b) => a -> Combine a b -> Combine a b -> Combine a b -> Bool
combineSemigroupAssoc x a b c = unCombine (a <> (b <> c)) x == unCombine ((a <> b) <> c) x
Implement the property that needs testing
genString :: Gen String
genString = arbitrary
prop_combineSemigroupAssoc :: Property
prop_combineSemigroupAssoc = forAll genString (combineSemigroupAssoc :: CombineAssoc)
and finally run quickCheck
quickCheck prop_combineSemigroupAssoc
Thinks I still need help with
Upvotes: 0
Views: 71
Reputation: 152707
I recommend writing your property in terms of Fun
:
type SS = Fun String String -- just to shorten things a bit
prop_CombineAssoc :: SS -> SS -> SS -> String -> Bool
prop_CombineAssoc f_ g_ h_ s =
unCombine (f <> (g <> h)) s == unCombine ((f <> g) <> h) s
where
[f, g, h] = map (Combine . applyFun) [f_, g_, h_]
The above property passes, but for fun, here's what it looks like for a failure. To get this output, I changed (f <> (g <> h))
to just f
.
> quickCheck prop_CombineAssoc
*** Failed! Falsified (after 3 tests and 16 shrinks):
{_->""}
{_->""}
{_->"a"}
""
As you can see, the Show
instance for Fun
is more informative than simply returning a constant String
, as your instance for Combine
does.
Upvotes: 0