haskell - 重叠实例的问题

标签 haskell

我目前正在从事一个项目,在该项目中我派生了类的一些实例。由于该类只有一种方法,除了少数特定情况外,具有相同的定义,因此我尝试定义一个可重叠的通用实例,然后定义需要重叠的实例。

这不起作用,因为我收到重叠实例错误。通过进行一些测试,我们遇到了这个简化的示例,它几乎相当于我原来的问题:

{-# LANGUAGE FlexibleInstances, UndecidableInstances, MultiParamTypeClasses #-}

module Instance where

data Id a = Id a String

data C a = C a

class Bad a b where
  bad :: a -> String

instance {-# OVERLAPPABLE #-} Bad a b where
  bad = \_ -> "Default case"

instance {-# OVERLAPPING #-} Bad (Id a) (C a) where
  bad = \_ -> "Id"

class Good a b where
  good :: a -> String

instance {-# OVERLAPPABLE #-} Good a b where
  good = \_ -> "Default case"

instance {-# OVERLAPPING #-} Good (Id a) b where
  good = \_ -> "Id"

test = let a = Id () "a"
       in putStrLn (good a) >> putStrLn (bad a)

(请注意,除非您注释第二个 Bad 实例,否则不会编译。)

Class Good 工作没有任何问题(测试输出“Id”)。如果我不删除 Bad 的第二个实例,我会得到:

Overlapping instances for Bad (Id ()) b0
    arising from a use of ‘bad’
  Matching instances:
    instance [overlappable] Bad a b -- Defined at Instance.hs:12:31
    instance [overlapping] Bad (Id a) (C a)
      -- Defined at Instance.hs:15:30
  (The choice depends on the instantiation of ‘b0’
   To pick the first instance above, use IncoherentInstances
   when compiling the other instance declarations)
  In the first argument of ‘putStrLn’, namely ‘(bad a)’
  In the second argument of ‘(>>)’, namely ‘putStrLn (bad a)’
  In the expression: putStrLn (good a) >> putStrLn (bad a)

我不明白的是为什么会发生这种情况,因为它们之间的唯一区别是第二类参数的附加限制。

此外,可重叠实例的目的不是为了避免重叠错误吗?

问候

最佳答案

根据我上面的评论,我认为你的编译指示应该有 AllowAmbigouslyTypes 而不是 UndecidableInstances, 否则你会得到一个不同的错误(至少我在 GHC 8.0.1 上是这样),与函数签名中的 b 不明确有关 bad::Bad a b => a -> String

AmbigouslyTypes 允许您为使用时不明确的函数编写签名。 相反,歧义性检查被移至调用站点。这对于像 TypeApplications 这样的东西非常有效 来指定那些不明确的变量。在这种情况下,bad 总是不明确的,所以我们需要这个 pragma 移动到 调用站点的错误消息。现在,我有和你一样的信息。


即使使用 OVERLAPPABLEOVERLAPPING Haskell 提示的原因是,取决于 b 的实例化方式(尚未被实例化) 指定),它将选择 Bad 的两个实例之一。换句话说,您可能希望bC a统一, 就像你不能做的那样,所以 Haskell 举起双手并说“你还没有告诉我足够多的关于 b 的信息,让我 能够选择 Bad 的最具体实例。

另一方面,即使不知道 b,Haskell 也知道 Good a bGood (Id a) b 实例中的哪一个是更多的 具体 - 它始终是第二个(即使不知道 b 是什么)。

我真的建议您阅读有关 overlapping instances 的文档 因为它解释了整个算法。


您通常可以使用诸如 TypeApplications(指定 b)之类的方法来解决这些问题,或者将您的类型类转换为类型系列。

关于haskell - 重叠实例的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39230522/

相关文章:

haskell - 是否使用以 "_"(下划线)开头的模式名称来记录/鼓励/便携的忽略结果?

haskell - Maybe 的可存储实例

haskell - Haskell 中用于确定是否重复的显式递归

haskell - 创建多态函数的事件流 - 可能吗?如果是,如何?

haskell - 如何正确收集Hxt程序的命令行选项?

haskell - 处理时间和日期的更简单方法?

linux - 如何将 Visual Studio Code 与 Haskell 和 Docker 结合使用

使用 GHCi 调试 Haskell 程序中的无限循环

haskell - 在 Data.Pool 中,如果创建新资源的操作抛出异常,会发生什么情况?

haskell - 需要一种有效的方法将 (Seq Data.Text) 转换为 Data.Text