【问题标题】:How to tell Haskell to not import the same instance from two modules?如何告诉 Haskell 不要从两个模块导入同一个实例?
【发布时间】:2013-05-08 09:46:57
【问题描述】:

我正在使用以下类型类:

module T where
class T a where
  v :: a

我实现的T Int 的一个实例:

import T
import A (av)

instance T Int where
  v = 0

main = putStrLn (av ++ show v)

还有一个我想从中使用值的模块,它也有一个 T Int 的实例。

module A where
import T
instance T Int where
  v = 0
av = "value from A"

问题是这不起作用:

$ runghc Main.hs 

Main.hs:4:9:
    Duplicate instance declarations:
      instance T Int -- Defined at Main.hs:4:9-13
      instance T Int -- Defined at A.hs:3:9-13

Haskell 抱怨同一个实例有 2 个声明。如何告诉他不要从B导入实例,或者统一两个实例,或者只使用Main的实例?

【问题讨论】:

  • 不要这样做。正确的解决方案是只在一个地方声明实例。
  • @hammar:我没有写TB,但我想使用来自B的值,我想创建一个T的实例。跨度>
  • 啊,这让事情变得更棘手了。在这种情况下,您可以创建一个 newtype 包装现有类型,并为 newtype 编写您的实例。

标签: haskell namespaces typeclass name-conflict


【解决方案1】:

不幸的是,您无法控制实例的导入和导出方式;见Do Haskell imports have side effects?

这意味着您必须重构代码以确保实例仅在一个文件中定义。一般来说,最好只在定义类或数据类型的文件中定义一个实例——事实上,甚至有一个关于不遵循此规则的“孤立”实例的警告。 (请查看Orphaned instances in Haskell,详细讨论为什么应该避免孤立实例。)

但是,如果由于某种原因无法做到这一点,您仍然可以随意选择其中一个文件来保留它,甚至可以创建一个新模块以供需要该特定实例的所有文件导入。

更一般地说,您将如何处理这两个实例做了不同事情的可能性,例如:

instance T Int where v = 0
{- And in a different file: -}
instance T Int where v = 1

在不显着改变 Haskell 类型类系统的工作方式的情况下,确实没有直接明显的方法可以消除这两者的歧义。

由于您自己编写了其中一个实例,因此只需删除该实例即可。由于它与预定义的相同,因此只需将该模块导入到您需要使用它的任何位置。

【讨论】:

  • “这意味着您必须重构代码以确保实例仅在一个文件中定义。”我怎样才能做到这一点?我没有写TB
  • 哦。然后,是的,这很糟糕。这就是为什么您不应该编写孤立实例的原因。我会使用具有孤儿实例的模块提交一个关于此的错误 - 即具有实例但未定义类或类型的模块。
  • @Dog:实际上,也许我误解了你的问题。由于您编写了其中一个实例,因此只需将其删除即可。如果需要,请写给newtype
猜你喜欢
  • 1970-01-01
  • 2021-04-20
  • 2014-01-03
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 2018-03-01
  • 2018-01-21
  • 1970-01-01
相关资源
最近更新 更多