Monoid类型类

时间:2020-07-11 09:16:51

标签: haskell monoids

我正在尝试使用https://en.wikibooks.org/wiki/Haskell/Monoids这个页面在Haskell中使用monoid。我在终端机上输入了以下信息(在导入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)

但是,当我尝试Sum 5 <> Sum 6 <> Sum 10时,会收到以下消息:

<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

我不知道这些错误是什么,以及为什么Sum 5 <> Sum 6 <> Sum 10无法正常工作。

1 个答案:

答案 0 :(得分:5)

问题是您正在使用自己的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文件中并通过:l xxx.hs加载到GHCi中进行测试可能是一个更好的主意。如果您尝试将此程序作为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