Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could not deduce (Semigroup (Optional a)) arising from the superclasses of an instance declaration

Tags:

haskell

The following code from "Haskell Programming: From first principles" fails to compile:

module Learn where
import Data.Semigroup
import Data.Monoid

-- Exercise: Optional Monoid
data Optional a = Nada
                | Only a
                deriving (Eq, Show)

instance Monoid a => Monoid (Optional a) where
 mempty = Nada
 mappend Nada Nada = Nada
 mappend (Only a) Nada = Only $ mappend a mempty
 mappend Nada (Only a) = Only $ mappend mempty a
 mappend (Only a) (Only b) = Only $ mappend a b

It gives the following error:

intermission.hs:11:10: error:
    • Could not deduce (Semigroup (Optional a))
        arising from the superclasses of an instance declaration
      from the context: Monoid a
        bound by the instance declaration at intermission.hs:11:10-40
    • In the instance declaration for ‘Monoid (Optional a)’
   |
11 | instance Monoid a => Monoid (Optional a) where
   |   

In order to stop ghc from complaining, I had to create a semigroup instance of Optional a and define "<>". This doesn't quite make sense to me and was wondering if there was something I was overlooking.

like image 261
jarvin Avatar asked Sep 08 '18 17:09

jarvin


2 Answers

"NOTE: Semigroup is a superclass of Monoid since base-4.11.0.0."

The list of superclasses in has been evolving slowly. As new useful classes are proposed, the API for older classes is updated to reflect their relationships. This has the unfortunate effect of breaking older code. Base 4.11.1.0 was released in April of 2018 with this breaking change to Monoid.

like image 152
John F. Miller Avatar answered Nov 03 '22 04:11

John F. Miller


Here is the solution:

import Data.Monoid

data Optional a = Nada | Only a deriving (Eq, Show)

instance Monoid a => Monoid (Optional a) where
   mempty = Nada

instance Semigroup a => Semigroup (Optional a) where
  Nada <> (Only a) = Only a
  (Only a) <> Nada = Only a
  (Only a) <> (Only a') = Only (a <> a')
  Nada <> Nada = Nada

main :: IO ()
main = do
  print $ Only (Sum 1) `mappend` Only (Sum 1)
like image 43
Chandan Avatar answered Nov 03 '22 04:11

Chandan