0

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.

Larynx
  • 398
  • 1
  • 12
  • 3
    Check the `Writer` type; `Three a b c` is ismorphic to `Writer (a, b) c` and `Three' a b` is ismorphic to `Writer (a, b) b`. – chepner Oct 24 '20 at 13:56
  • 4
    `Three' a b` is isomorphic to `Writer (a, b) b`, but can't use the `Monad (Writer (a, b))` instance because the two `b`s are tied together. (Consider, e.g. `return :: (Monoid a, Monoid b) => c -> Writer (a, b) c`, which can't be realized with `Three'`.) BUT it is also isomorphic to [`Product (Writer a) Identity b`](https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Functor-Product.html), and you *can* use that `Monad` instance. – Daniel Wagner Oct 24 '20 at 16:22

0 Answers0