How can defined a Log-instance for (a, b) under the assumption, which a, b are already Log-instance?

Viewed 89

It's a homework for us to understanding instance, but as the title, I don't know 'How to define a Log-instance (a, b), which a and b is also Log-instance'.

data FullLog = FullLog [String] deriving Show

instance Semigroup FullLog where
  FullLog a <> FullLog b = FullLog (a ++ b)

instance Monoid FullLog where
  mempty = FullLog []

instance Log FullLog where
  logMsg x = FullLog [x]

-- *Main> fib 3 :: (Int, ReverseLog)
-- (3,ReverseLog ["fib 3","fib 1","fib 2","fib 0","fib 1"])
-- instance Log ReverseLog where
data ReverseLog = ReverseLog [String] deriving Show

instance Semigroup ReverseLog where
  ReverseLog a <> ReverseLog b = ReverseLog (b ++ a)

instance Monoid ReverseLog where
  mempty = ReverseLog []

instance Log ReverseLog where
  logMsg x = ReverseLog [x]


-- *Main> fib 3 :: (Int, LastMsgLog)
-- (3,LastMsgLog (Just "fib 3"))
--instance Log LastMsgLog where
data LastMsgLog = LastMsgLog (Maybe String) deriving Show

instance Semigroup LastMsgLog where
  LastMsgLog a <> LastMsgLog b = LastMsgLog (b)

instance Monoid LastMsgLog where
  mempty = LastMsgLog (Nothing)

instance Log LastMsgLog where
  logMsg x = LastMsgLog (Just x)

-- *Main> fib 3 :: (Int, CountLog)
-- (3,CountLog 5)
--instance Log CountLog where
data CountLog = CountLog Int deriving Show

instance Semigroup CountLog where
  CountLog a <> CountLog b = CountLog (a+b)

instance Monoid CountLog where
  mempty = CountLog 0

instance Log CountLog where
  logMsg x = CountLog 1

I have already finished 4 instance of Log : FullLog, ReverseLog, LastMsgLog and CountLog, Now I need to define Log-instance(a,b), where a and b can be any of FullLog, ReverseLog, LastMsgLog and CountLog.

I have tried directly define Log (a,b), and error is like Not in scope: data constructor ‘Log’, that's obvious.

So I tried to define a type MixLog like above

data MixLog = MixLog (a, b) deriving Show

instance MixLog :: (Log a, Log b) => Log (a, b) where
  Log ( a,  b) <> Log ( c,  d ) = Log (a <> c, b <> d)

but also error: parse error on input ‘::’

So now I'm confused, how can I make type constraints?

Thank you!

1 Answers

If you want to make MixLog an instance of Log, you thus can implement this as:

data MixLog a b = MixLog (a, b)

instance (Log a, Log b) => Log (MixLog a b) where
  logMsg x = MixLog (logMsg x, logMsg x)

You thus need to specify type parameters a and b in your MixLog type constructor, furthermore we define the logMsg :: Log c => String -> c function with MixLog objects, so we construct a MixLog with a 2-tuple where both elements are the result of a logMsg x call (or we can implement this differently).

You can however omit the MixLog data constructor, and implement this as:

instance (Log a, Log b) => Log (a,b) where
  logMsg x = (logMsg x, logMsg x)

There is nothing special about a 2-tuple, so we can use its type constructor, and data constructor.

Related