I tried to write some instances for two datatypes. (Three
and Three'
) But
I'm having a hard time implementing an Applicative (and Monad) instance.
With a little help, I think I can solve the problem.
Datatypes are as follows.
data Three a b c = T a b c deriving (Eq, Show)
data Three' a b = T' a b b deriving (Eq, Show)
And my code is as follows. The first is for the datatype Three
. I think everything is fine except Monad instance.
data Three a b c = Three a b c deriving (Show, Eq)
-- Semigroup instance
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')
-- Monoid instance
instance (Monoid a, Monoid b, Monoid c) => Monoid (Three a b c) where
mempty = Three mempty mempty mempty
-- Functor instance
instance Functor (Three a b) where
fmap f (Three a b c) = Three a b (f c)
-- Applicative instance
instance (Monoid a, Monoid b) => Applicative (Three a b) where
pure = Three mempty mempty
(Three a b f) <*> (Three a' b' c') = Three (a <> a') (b <> b') (f c')
-- Monad instance (<----- Here! Difficult!)
-- Foldable instance
instance Foldable (Three a b) where
foldMap f (Three a b c) = f c
-- Arbitrary instance
instance (Arbitrary a, Arbitrary b, Arbitrary c) => Arbitrary (Three a b c) where
arbitrary = Three <$> arbitrary <*> arbitrary <*> arbitrary
-- EqProp instance
instance (Eq a, Eq b, Eq c) => EqProp (Three a b c) where
(=-=) = eq
-- Test
test_Three = do
let trigger = undefined :: Three (Sum Int, String, Sum Int) (Sum Int, String, Sum Int) (Sum Int, String, Sum Int)
quickBatch $ monoid trigger
quickBatch $ functor trigger
quickBatch $ applicative trigger
-- quickBatch $ monad trigger -- Monad instance was not yet implemented.
The second is for the datatype Three'
. I couldn't implement both Applicative and Monad instances here. The number of arguments confused me. How can I implement the Applicative and Monad instances for Three'
datatytpe here?
data Three' a b = Three' a b b deriving (Show, Eq)
-- Semigroup instance
instance (Semigroup a, Semigroup b) => Semigroup (Three' a b) where
Three' a b c <> Three' a' b' c' = Three' (a <> a') (b <> b') (c <> c')
-- Three' a b b <> Three' a' b' b' = Three' (a <> a') (b <> b') (b <> b') -- TODO: Error
-- Monoid instance
instance (Monoid a, Monoid b) => Monoid (Three' a b) where
mempty = Three' mempty mempty mempty
-- Functor instance
instance Functor (Three' a) where
fmap f (Three' a b c) = Three' a (f b) (f c)
-- Applicative instance (<-------HERE! Difficult.)
{-
-- the first trial - incorrect
instance (Monoid a) => Applicative (Three' a) where
pure = Three' mempty mempty
(Three' a f g) <*> (Three' a' b' c') = Three' (a <> a') (f b') (g c')
-}
{-
-- the second trial - incorrect
instance (Monoid a) => Applicative (Three' a) where
pure = Three' mempty mempty
(Three' a b f) <*> (Three' a' b' c') = Three' (a <> a') (b <> b') (f c')
-}
-- Monad instance (<-------HERE! Difficult.)
-- Foldable instance
instance Foldable (Three' a) where
foldMap f (Three' a b b') = f b `mappend` f b'
-- Arbitrary instance
instance (Arbitrary a, Arbitrary b) => Arbitrary (Three' a b) where
arbitrary = Three' <$> arbitrary <*> arbitrary <*> arbitrary
-- EqProp instance
instance (Eq a, Eq b) => EqProp (Three' a b) where (=-=) = eq
-- Test
test_Three' = do
let trigger = undefined :: Three' (Sum Int, String, Sum Int) (Sum Int, String, Sum Int)
quickBatch $ monoid trigger
quickBatch $ functor trigger
Many thanks.