简体   繁体   中英

The Monoid type class

I am trying to play around with monoids in Haskell, using this page: https://en.wikibooks.org/wiki/Haskell/Monoids . I entered the following information in the terminal (after importing Data.Monoid ):

class Monoid a where
    mempty  :: a
    mappend :: a -> a -> a
    mconcat :: [a] -> a
    mconcat = foldr mappend memptyhere
newtype Sum a = Sum { getSum :: a }
instance Num a => Monoid (Sum a) where
     mempty = Sum 0
     Sum x `mappend` Sum y = Sum (x + y)

However, when I then try Sum 5 <> Sum 6 <> Sum 10 , I receive the following message:

<interactive>:115:1: error:
• Non type-variable argument in the constraint: Semigroup (Sum a)
  (Use FlexibleContexts to permit this)
• When checking the inferred type
    it :: forall a. (Semigroup (Sum a), Num a) => Sum a

I don't understand what errors these are, and why Sum 5 <> Sum 6 <> Sum 10 didn't work.

The problem is that you are using your own Sum type and Monoid type class with an operator <> that is not the same function as your version of mappend . If you were to enter this program in a multi-line GHCi prompt:

> :{
Prelude| ...paste your program in here...
Prelude| :}
>

and then try this instead:

> Sum 5 `mappend` Sum 6 `mappend` Sum 7
Sum 5 `mappend` Sum 6 `mappend` Sum 7 :: Num a => Sum a

there would be no error. If you added a deriving (Show) to your Sum type, you'd even get the answer you're looking for!

Ok, modules loaded: none.
λ> :{
Prelude| class Monoid a where
Prelude|     mempty  :: a
Prelude|     mappend :: a -> a -> a
Prelude|     mconcat :: [a] -> a
Prelude|     mconcat = foldr mappend mempty
Prelude| newtype Sum a = Sum { getSum :: a } deriving (Show)
Prelude| instance Num a => Monoid (Sum a) where
Prelude|      mempty = Sum 0
Prelude|      Sum x `mappend` Sum y = Sum (x + y)
Prelude| :}
λ> Sum 5 `mappend` Sum 6 `mappend` Sum 7
Sum {getSum = 18}
λ> 

The rules for overriding library definitions in GHCi can be a little complicated, so it might be a better idea to put this into a xxx.hs file and load it into GHCi with :l xxx.hs for testing. If you'd tried to load this program as a xxx.hs file, you would have gotten much clearer messages about the problem:

MonoidExample2.hs:7:19-24: error:
    Ambiguous occurrence ‘Monoid’
    It could refer to
       either ‘Prelude.Monoid’,
              imported from ‘Prelude’ at MonoidExample2.hs:1:1
              (and originally defined in ‘GHC.Base’)
           or ‘Main.Monoid’, defined at MonoidExample2.hs:1:1

Then, you could use the special import Prelude syntax to hide the library definitions you didn't want. The following version works as a self-contained program:

import Prelude hiding (Monoid, mempty, mappend, mconcat, (<>))

class Monoid a where
  mempty  :: a
  mappend :: a -> a -> a
  mconcat :: [a] -> a
  mconcat = foldr mappend mempty

newtype Sum a = Sum { getSum :: a } deriving (Show)

instance Num a => Monoid (Sum a) where
  mempty = Sum 0
  Sum x `mappend` Sum y = Sum (x + y)

(<>) :: Monoid a => a -> a -> a
(<>) = mappend

main :: IO ()
main = print $ Sum 5 <> Sum 6 <> Sum 10

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