Проблема в том, что вы используете свой собственный тип Sum
и класс типа Monoid
с оператором <>
, который является не той же функцией, что и ваша версия mappend
. Если вы введете эту программу в многострочном приглашении GHCi:
> :{
Prelude| ...paste your program in here...
Prelude| :}
>
, а затем попробуете вместо этого:
> Sum 5 `mappend` Sum 6 `mappend` Sum 7
Sum 5 `mappend` Sum 6 `mappend` Sum 7 :: Num a => Sum a
, ошибки не будет. Если вы добавите deriving (Show)
к вашему типу Sum
, вы даже получите ответ, который ищете!
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}
λ>
Правила переопределения определений библиотек в GHCi могут быть немного сложными, поэтому было бы лучше поместить это в файл xxx.hs
и загрузить его в GHCi с :l xxx.hs
для тестирования. Если бы вы попытались загрузить эту программу как файл xxx.hs
, вы бы получили гораздо более четкие сообщения о проблеме:
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
Затем вы могли бы использовать специальный синтаксис import Prelude
, чтобы скрыть определения библиотеки, которые вам не нужны. Следующая версия работает как автономная программа:
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