简体   繁体   中英

How to write Semigroup instance for this data type?

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?

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)

You can shadow Monoid 's (<>) this way:

import Data.Monoid hiding ((<>))

Then when you import Data.Semigroup , you will have just one (<>) in scope: the one from Data.Semigroup .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM