【问题标题】:Could not deduce (Semigroup (Optional a)) arising from the superclasses of an instance declaration无法从实例声明的超类中推断出(半群(可选 a))
【发布时间】:2018-09-08 17:51:26
【问题描述】:

“Haskell Programming: From first principle”中的以下代码编译失败:

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

它给出了以下错误:

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
   |   

为了阻止 ghc 抱怨,我必须创建 Optional a 的半群实例并定义“”。这对我来说不太有意义,我想知道我是否忽略了一些东西。

【问题讨论】:

  • 根据幺半群定律,mappend a mempty 可以简化为 a

标签: haskell


【解决方案1】:

解决办法如下:

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)

【讨论】:

  • 我对 Haskell 没有真正的了解,但你能详细说明你的解决方案吗?指点哪行能解决问题?或者哪些行不起作用。对于试图理解问题的人来说,这比在他们的代码中复制粘贴你的答案更容易掌握。
  • @Fjarlaegur 解决问题的部分是instance Semigroup。在 OP 的代码中,他有一个 Monoid 的实例,就像 Chandan 在这里的回答一样。不同的是,Chandan 还添加了 Semigroup 的实例。正如 John F. Miller 回答的那样,过去有一个 Monoid 实例就足够了,但现在情况发生了变化,您还需要一个 Semigroup 实例。但是,OP 的 Monoid 实例中的逻辑与 Chandan 的 Semigroup 实例中的逻辑相同(不要被 mappend&lt;&gt; 混淆,它们是同一回事)。
【解决方案2】:

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

其中的超类列表一直在缓慢发展。随着新的有用类的提出,旧类的 API 会更新以反映它们的关系。这具有破坏旧代码的不幸影响。 Base 4.11.1.0 于 2018 年 4 月发布,对 Monoid 进行了重大更改。

【讨论】:

  • 有没有办法在不创建 Optional a 的虚拟半群实例的情况下创建一个幺半群实例?
  • @jarvin:换句话说,您应该使用您当前对mappend 的定义在Semigroup 实例中定义&lt;&gt;,并在Monoid 实例中定义mempty。你可以忽略mappend,因为它现在只是出于兼容性原因,它的默认实现是mappend = (&lt;&gt;)
猜你喜欢
  • 1970-01-01
  • 2010-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2012-03-13
  • 2019-06-29
  • 1970-01-01
相关资源
最近更新 更多