首页 > 解决方案 > 避免重叠实例的更好方法是什么

问题描述

我正在尝试实现 Integral 类型类的 2 元组和 3 元组的行为。我还想为单个值定义行为,但我的方法似乎会导致类型错误。

{-# LANGUAGE FlexibleInstances #-}

class MyClass a where
    prints :: a -> String

instance (Show n, Integral n) => MyClass (n, n) where
    prints = show

instance (Show n, Integral n) => MyClass (n, n, n) where
    prints = show

按预期工作。但是当我添加

{-# LANGUAGE UndecidableInstances #-} -- Adding this or else it wont compile

instance (Show n, Integral n) => MyClass n where
    prints = show

我收到以下错误

*Main> prints 1
"1"
*Main> prints (1,1)

<interactive>:132:1: error:
    • Overlapping instances for MyClass (Integer, Integer)
        arising from a use of ‘prints’
      Matching instances:
        instance [safe] (Show n, Integral n) => MyClass n
          -- Defined at question.hs:12:10
        instance [safe] (Show n, Integral n) => MyClass (n, n)
          -- Defined at question.hs:6:10
    • In the expression: prints (1, 1)
      In an equation for ‘it’: it = prints (1, 1)

这些怎么可能是重叠的实例?以这种方式定义时,类型是否需要包装在构造函数中?有没有更好的方法来实现这样的目标?

标签: haskell

解决方案


错误消息列出了重叠的实例:

  Matching instances:
    instance [safe] (Show n, Integral n) => MyClass n
      -- Defined at question.hs:12:10
    instance [safe] (Show n, Integral n) => MyClass (n, n)
      -- Defined at question.hs:6:10

在这个特定示例中,这可能不是问题,因为两者具有相同的实现 ( show)。然而,编译器并不知道这一点。

想象一下,您有两个不同的实例。例如,为了论证,您可能已将其中一个实例定义为:

prints x = show x ++ "foo"

现在,当你 go 时prints (1,1),编译器不知道要选择哪个实例。它不能随意选择一个,因为输出可能会有所不同。

在 OP 案例中,我认为最简单的解决方案是删除特定实例(即MyClass (n, n)MyClass (n, n, n)),因为更一般的实例也涵盖了这些特定情况,并且具有相同的行为。


推荐阅读