无法推断(Semigroup(可选a))由实例声明的超类引起

jar*_*vin 9 haskell

来自"Haskell编程:来自第一原理"的以下代码无法编译:

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
Run Code Online (Sandbox Code Playgroud)

它给出以下错误:

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
   |   
Run Code Online (Sandbox Code Playgroud)

为了阻止ghc抱怨,我必须创建一个可选a的半群实例并定义"<>".这对我来说没有多大意义,并且想知道是否有一些我忽略的东西.

Joh*_*ler 9

" 注意:Semigroup是Monoid的超类,因为基数为4.11.0.0. "

超级班的名单一直在缓慢发展.随着新的有用类的提出,更新旧类的API以反映它们之间的关系.这有破坏旧代码的不幸影响.基础4.11.1.0于2018年4月发布,对Monoid进行了这一重大改变.

  • @jarvin:换句话说,你应该使用你现在为`mappend`定义的`Semigroup`实例定义`<>`,并在`Monoid`实例中定义`mempty`.您可以忽略`mappend`,因为它现在只是出于兼容性原因,它的默认实现是`mappend =(<>)`. (8认同)
  • 有没有办法创建一个monoid实例而不创建一个可选a的虚拟半群实例? (3认同)

小智 5

这是解决方案:

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)
Run Code Online (Sandbox Code Playgroud)

  • 我对 Haskell 没有真正的了解,但是您能详细说明您的解决方案吗?指出哪条线可以解决问题?或者哪些线路不起作用。对于试图理解问题的人来说,它更容易掌握,而不仅仅是将您的答案复制粘贴到他们的代码中。 (2认同)