"实例的例外(Num a)=>是的,不在哪里"代码行

时间:2014-12-19 12:37:55

标签: haskell

这很好用:

class YesNo a where
    yesNo :: a-> Bool

instance YesNo Bool where
    yesNo True = True
    yesNo _ = False

instance YesNo [a] where
    yesNo [] = False
    yesNo _ = True

instance YesNo (Maybe a) where
    yesNo Nothing = False
    yesNo _ = True

但我收到代码错误:

instance (Num a) => YesNo a where -- error is here
    yesNo 0 = False
    yesNo _ = True

异常消息:

ghci> :l src
[1 of 1] Compiling Main             ( src.hs, interpreted )

src.hs:16:21:
    Illegal instance declaration for `YesNo a'
      (All instance types must be of the form (T a1 ... an)
       where a1 ... an are *distinct type variables*,
       and each type variable appears at most once in the instance head.
       Use FlexibleInstances if you want to disable this.)
    In the instance declaration for `YesNo a'
Failed, modules loaded: none.
ghci>

我做错了什么?

3 个答案:

答案 0 :(得分:5)

您似乎正在努力使其成为Num实例的每个类型自动成为YesNo的实例。

不幸的是,你不能这样做。

您只能为特定类型声明实例。因此,您可以为IntDouble声明一个实例,但是您无法为每个Num"声明一个实例。

答案 1 :(得分:2)

正如错误消息已经指出的那样,有ghc个选项可以使您的实例声明完全合法(但是,如果您的ghc是{{3,则必须向其添加约束Eq a }})

ghci -XFlexibleInstances -XUndecidableInstances <your program> 

将以您期望的方式编译和工作。

为什么默认情况下不允许使用灵活且不可判定的实例?

  • 类型类 open ,可以在以后扩展。假设其他人会使用Num扩展instance (Num a) => Num [a]),例如fromInt x = [fromInt x]和组件添加等。然后我们会有重叠的实例:shoud yesNo [0]为{{1} }或True?因此,通过扩展一个类(False),其他类(Num)的实例突然重叠。这就是默认情况下不允许使用灵活实例的原因

  • 声明YesNo时,instance (Eq a, Num a) => YesNo a并不比Num a严格更小(更简单)。我和你知道检查YesNo a - ness的任何类型最终会产生一个aswer,但是再想一想,其他人(为什么不呢?)会添加一个实例YesNo。然后类型检查器会陷入循环:(YesNo a) => Num a where..这就是默认情况下不允许(可能)不可判定的实例的原因

因此,覆盖类型类定义的默认限制现在可能很有效,但将来会引起严重的搔痒。

答案 2 :(得分:1)

试试这个:

instance (Num a) => YesNo a where
    yesNo x | x == fromIntegral 0 = False
            | otherwise = True

问题是0不属于a类型。 但是,在Num的任何情况下,您都必须定义fromIntegral函数。