module Chapter21 where
import Test.Hspec
import Test.Hspec.Checkers
import Test.QuickCheck
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes
data Identity a =
Identity a
deriving (Eq, Ord, Show)
instance Arbitrary a => Arbitrary (Identity a) where
arbitrary = Identity <$> arbitrary
instance Eq a => EqProp (Identity a) where
(=-=) = eq
instance Semigroup a => Semigroup (Identity a) where
Identity a <> Identity a' = Identity $ a <> a'
instance Monoid a => Monoid (Identity a) where
mempty = Identity mempty
instance Functor Identity where
fmap f (Identity a) = Identity $ f a
instance Foldable Identity where
foldr f acc (Identity a) = f a acc
instance Traversable Identity where
traverse f (Identity a) = Identity <$> f a
data Constant a b = Constant
{ getConstant :: a
} deriving (Eq, Ord, Show)
instance Arbitrary a => Arbitrary (Constant a b) where
arbitrary = Constant <$> arbitrary
instance Eq a => EqProp (Constant a b) where
(=-=) = eq
instance Semigroup a => Semigroup (Constant a b) where
Constant a <> Constant a' = Constant $ a <> a'
instance Monoid a => Monoid (Constant a b) where
mempty = Constant mempty
instance Functor (Constant a) where
fmap _ (Constant a) = Constant a
instance Foldable (Constant a) where
foldr _ acc _ = acc
instance Traversable (Constant a) where
traverse _ (Constant a) = pure $ Constant a
data Optional a
= Nada
| Yep a
deriving (Eq, Ord, Show)
instance Arbitrary a => Arbitrary (Optional a) where
arbitrary = oneof [return Nada, Yep <$> arbitrary]
instance Eq a => EqProp (Optional a) where
(=-=) = eq
instance Semigroup a => Semigroup (Optional a) where
Nada <> Nada = Nada
Yep a <> Nada = Yep a
Nada <> Yep a = Yep a
Yep a <> Yep a' = Yep $ a <> a'
instance Semigroup a => Monoid (Optional a) where
mempty = Nada
instance Functor Optional where
fmap _ Nada = Nada
fmap f (Yep a) = Yep $ f a
instance Foldable Optional where
foldr _ acc Nada = acc
foldr f acc (Yep a) = f a acc
instance Traversable Optional where
traverse _ Nada = pure Nada
traverse f (Yep a) = Yep <$> f a
data List a
= Nil
| Cons a
(List a)
deriving (Eq, Ord, Show)
toMyList :: [a] -> List a
toMyList [] = Nil
toMyList (a:as) = Cons a (toMyList as)
take' :: Int -> List a -> List a
take' 0 _ = Nil
take' _ Nil = Nil
take' n (Cons a as) = Cons a (take' (n - 1) as)
instance Semigroup (List a) where
Nil <> ys = ys
Cons x xs <> ys = Cons x $ xs <> ys
instance Arbitrary a => Arbitrary (List a) where
arbitrary = toMyList <$> arbitrary
instance Eq a => EqProp (List a) where
xs =-= ys = take' 3000 xs `eq` take' 3000 ys
instance Functor List where
fmap _ Nil = Nil
fmap f (Cons a as) = Cons (f a) (fmap f as)
instance Foldable List where
foldr _ acc Nil = acc
foldr f acc (Cons a as) = f a (foldr f acc as)
instance Traversable List where
traverse f Nil = pure Nil
traverse f (Cons a as) = (Cons <$> f a) <*> traverse f as
data Three a b c =
Three a
b
c
deriving (Eq, Ord, Show)
instance (Arbitrary a, Arbitrary b, Arbitrary c) =>
Arbitrary (Three a b c) where
arbitrary = Three <$> arbitrary <*> arbitrary <*> arbitrary
instance (Eq a, Eq b, Eq c) => EqProp (Three a b c) where
(=-=) = eq
instance (Semigroup a, Semigroup b, Semigroup c) =>
Semigroup (Three a b c) where
Three a b c <> Three a' b' c' = Three (a <> a') (b <> b') (c <> c')
instance (Monoid a, Monoid b, Monoid c) => Monoid (Three a b c) where
mempty = Three mempty mempty mempty
instance Functor (Three a b) where
fmap f (Three a b c) = Three a b (f c)
instance Foldable (Three a b) where
foldr f acc (Three _ _ c) = f c acc
instance Traversable (Three a b) where
traverse f (Three a b c) = Three a b <$> f c
data Pair a b =
Pair a
b
deriving (Eq, Ord, Show)
instance (Arbitrary a, Arbitrary b) => Arbitrary (Pair a b) where
arbitrary = Pair <$> arbitrary <*> arbitrary
instance (Eq a, Eq b) => EqProp (Pair a b) where
(=-=) = eq
instance (Semigroup a, Semigroup b) => Semigroup (Pair a b) where
Pair a b <> Pair a' b' = Pair (a <> a') (b <> b')
instance (Monoid a, Monoid b) => Monoid (Pair a b) where
mempty = Pair mempty mempty
instance Functor (Pair a) where
fmap f (Pair a b) = Pair a (f b)
instance Foldable (Pair a) where
foldr f acc (Pair _ b) = f b acc
instance Traversable (Pair a) where
traverse f (Pair a b) = Pair a <$> f b
data Big a b =
Big a
b
b
deriving (Eq, Ord, Show)
instance (Arbitrary a, Arbitrary b) => Arbitrary (Big a b) where
arbitrary = Big <$> arbitrary <*> arbitrary <*> arbitrary
instance (Eq a, Eq b) => EqProp (Big a b) where
(=-=) = eq
instance (Semigroup a, Semigroup b) => Semigroup (Big a b) where
Big a b1 b2 <> Big a' b1' b2' = Big (a <> a') (b1 <> b1') (b2 <> b2')
instance (Monoid a, Monoid b) => Monoid (Big a b) where
mempty = Big mempty mempty mempty
instance Functor (Big a) where
fmap f (Big a b1 b2) = Big a (f b1) (f b2)
instance Foldable (Big a) where
foldr f acc (Big _ b1 b2) = f b1 (f b2 acc)
instance Traversable (Big a) where
traverse f (Big a b1 b2) = Big a <$> f b1 <*> f b2
data Bigger a b =
Bigger a
b
b
b
deriving (Eq, Ord, Show)
instance (Arbitrary a, Arbitrary b) => Arbitrary (Bigger a b) where
arbitrary = Bigger <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
instance (Eq a, Eq b) => EqProp (Bigger a b) where
(=-=) = eq
instance (Semigroup a, Semigroup b) => Semigroup (Bigger a b) where
Bigger a b1 b2 b3 <> Bigger a' b1' b2' b3' =
Bigger (a <> a') (b1 <> b1') (b2 <> b2') (b3 <> b3')
instance (Monoid a, Monoid b) => Monoid (Bigger a b) where
mempty = Bigger mempty mempty mempty mempty
instance Functor (Bigger a) where
fmap f (Bigger a b1 b2 b3) = Bigger a (f b1) (f b2) (f b3)
instance Foldable (Bigger a) where
foldr f acc (Bigger _ b1 b2 b3) = f b1 (f b2 (f b3 acc))
instance Traversable (Bigger a) where
traverse f (Bigger a b1 b2 b3) = Bigger a <$> f b1 <*> f b2 <*> f b3
data S n a =
S (n a)
a
deriving (Eq, Ord, Show)
instance (Arbitrary a, Arbitrary (n a)) => Arbitrary (S n a) where
arbitrary = S <$> arbitrary <*> arbitrary
instance (Eq a, Eq (n a)) => EqProp (S n a) where
(=-=) = eq
instance (Semigroup a, Semigroup (n a)) => Semigroup (S n a) where
S n a <> S n' a' = S (n <> n') (a <> a')
instance (Monoid a, Monoid (n a)) => Monoid (S n a) where
mempty = S mempty mempty
instance Functor n => Functor (S n) where
fmap f (S n a) = S (f <$> n) (f a)
instance Foldable n => Foldable (S n) where
foldr f acc (S n a) = foldr f (f a acc) n
instance Traversable n => Traversable (S n) where
traverse f (S n a) = S <$> traverse f n <*> f a
data Tree a
= Empty
| Leaf a
| Node (Tree a)
a
(Tree a)
deriving (Eq, Ord, Show)
instance Arbitrary a => Arbitrary (Tree a) where
arbitrary = do
a <- arbitrary
left <- arbitrary
right <- arbitrary
frequency
[(5, return Empty), (5, return $ Leaf a), (1, return $ Node left a right)]
instance Eq a => EqProp (Tree a) where
(=-=) = eq
instance Semigroup (Tree a) where
Empty <> tree = tree
Leaf a <> tree = Node Empty a tree
Node left a right <> tree = Node left a (right <> tree)
instance Monoid (Tree a) where
mempty = Empty
instance Functor Tree where
fmap _ Empty = Empty
fmap f (Leaf a) = Leaf $ f a
fmap f (Node left a right) = Node (fmap f left) (f a) (fmap f right)
instance Foldable Tree where
foldr _ acc Empty = acc
foldr f acc (Leaf a) = f a acc
foldr f acc (Node left a right) = foldr f (f a (foldr f acc right)) left
instance Traversable Tree where
traverse f Empty = pure Empty
traverse f (Leaf a) = Leaf <$> f a
traverse f (Node left a right) =
Node <$> traverse f left <*> f a <*> traverse f right
spec :: SpecWith ()
spec = do
describe "Identity" $
testBatch $ traversable (undefined :: Identity (String, String, String))
describe "Constant" $
testBatch $ traversable (undefined :: Constant Int (String, String, String))
describe "Optional" $
testBatch $ traversable (undefined :: Optional (String, String, String))
describe "List" $
testBatch $ traversable (undefined :: List (String, String, String))
describe "Three" $
testBatch $
traversable (undefined :: Three Int Int (String, String, String))
describe "Pair" $
testBatch $ traversable (undefined :: Pair Int (String, String, String))
describe "Big" $
testBatch $ traversable (undefined :: Big Int (String, String, String))
describe "Bigger" $
testBatch $ traversable (undefined :: Bigger Int (String, String, String))
describe "S" $
testBatch $ traversable (undefined :: S [] (String, String, String))
describe "Tree" $
testBatch $ traversable (undefined :: Tree (String, String, String))