I'm trying to do one of the Semigroup exercises in Haskell Book (Chapter 15, "Monoid, Semigroup") but I'm stuck. The following is given:
newtype Combine a b =
Combine { unCombine :: (a -> b) }
and I'm supposed to write the Semigroup
instance for Combine
.
And then book says that it must behave like the following:
Prelude> let f = Combine $ \n -> Sum (n + 1)
Prelude> let g = Combine $ \n -> Sum (n - 1)
Prelude> unCombine (f <> g) $ 0
Sum {getSum = 0}
Prelude> unCombine (f <> g) $ 1
Sum {getSum = 2}
Prelude> unCombine (f <> f) $ 1
Sum {getSum = 4}
Prelude> unCombine (g <> f) $ 1
Sum {getSum = 2}
So I first started with a wrong solution that type checks:
instance Semigroup (Combine a b) where
Combine f <> Combine g = Combine f
That does not what is expected of course, but hopefully a step in the right direction. And my thinking is something like the following, in pseudocode:
instance Semigroup (Combine a b) where
(Combine f) <> (Combine g) = Combine (SOMETHING)
That SOMETHING being: f
and g
appended, whatever that concrete append operation is (it depends on f
and g
); so I think this requires <>
from Data.Monoid
, but I already have import Data.Semigroup
in my code, and therefore <>
from Data.Monoid
coincides with the one from Data.Semigroup
. So what am I supposed to do?
I tried to find out how I can state something like "Combine (f Monoid's <> g)", but couldn't find out.
The book also states unless I'm using GHC 8.x, I'll have to import Semigroup
and that I might have "shadow" the <>
from Monoid
; but I'm struggling to find out how to have this effect.
Any ideas?