如何告诉Haskell不从两个模块导入相同的实例?

Dog*_*Dog 7 haskell namespaces typeclass name-conflict

我正在使用以下类型类:

module T where
class T a where
  v :: a
Run Code Online (Sandbox Code Playgroud)

T Int我实现的一个实例:

import T
import A (av)

instance T Int where
  v = 0

main = putStrLn (av ++ show v)
Run Code Online (Sandbox Code Playgroud)

还有一个模块,我想使用一个值,也有一个实例T Int.

module A where
import T
instance T Int where
  v = 0
av = "value from A"
Run Code Online (Sandbox Code Playgroud)

问题是这不起作用:

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

Haskell抱怨同一个实例有2个声明.我如何告诉他不要从中导入实例B,或统一这两个实例,或仅使用实例Main

Tik*_*vis 8

不幸的是,您无法控制实例的导入和导出方式; 看看Haskell进口有副作用吗?.

这意味着您必须重构代码以确保实例仅在一个文件中定义.通常,最好只在文件中定义一个定义类或数据类型的实例 - 事实上,甚至还有关于"孤儿"实例的警告,这些实例不遵循此规则.(查看Haskell中的孤立实例,深入讨论为什么要避免使用孤立实例.)

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

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

instance T Int where v = 0
{- And in a different file: -}
instance T Int where v = 1
Run Code Online (Sandbox Code Playgroud)

在没有显着改变Haskell类型类系统的工作方式的情况下,确实没有明显的方法可以消除歧义.

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

  • @Dog:实际上,也许我误解了你的问题.由于您编写了其中一个实例,只需删除它即可.如果必须,写一个`newtype`. (2认同)