Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write Semigroup instance for this data type?

Tags:

haskell

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?

like image 531
Emre Sevinç Avatar asked Dec 03 '22 14:12

Emre Sevinç


1 Answers

What they want is probably the addition of functions. For that, type b needs to be a Semigroup :

import Data.Semigroup

newtype Combine a b =
  Combine { unCombine :: (a -> b) }

instance Semigroup b => Semigroup (Combine a b) where
  (Combine f) <> (Combine g) = Combine (\x -> f x <> g x)
like image 74
V. Semeria Avatar answered Jan 06 '23 23:01

V. Semeria