没有因使用“==”而产生的(Eq a)实例

No instance for (Eq a) arising from a use of `=='

在下面的Haskell代码中:

import Data.List
import Data.Char

data EXP a = Empty | Symbol a
           deriving (Show, Eq, Ord)

test :: (Ord a) => EXP a -> [[a]]

test Empty = []
test (Symbol x) = [[x]]

value = (test Empty) == []

我收到以下错误:

problem.hs:12:10:
    No instance for (Ord a0) arising from a use of `test'
    The type variable `a0' is ambiguous
    Note: there are several potential instances:
      instance Ord a => Ord (EXP a) -- Defined at problem.hs:5:32
      instance Integral a => Ord (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
      instance Ord GeneralCategory -- Defined in `Data.Char'
      ...plus 26 others
    In the first argument of `(==)', namely `(test Empty)'
    In the expression: (test Empty) == []
    In an equation for `value': value = (test Empty) == []

problem.hs:12:22:
    No instance for (Eq a0) arising from a use of `=='
    The type variable `a0' is ambiguous
    Note: there are several potential instances:
      instance Eq a => Eq (EXP a) -- Defined at problem.hs:5:28
      instance Eq a => Eq (GHC.Real.Ratio a) -- Defined in `GHC.Real'
      instance Eq GeneralCategory -- Defined in `Data.Char'
      ...plus 26 others
    In the expression: (test Empty) == []
    In an equation for `value': value = (test Empty) == []
Failed, modules loaded: none.

但是如果我删除最后一行,那么代码是:

import Data.List
import Data.Char

data EXP a = Empty | Symbol a
           deriving (Show, Eq, Ord)

test :: (Ord a) => EXP a -> [[a]]

test Empty = []
test (Symbol x) = [[x]]

我可以在交互式提示中执行以下操作,不会出错:

Prelude> :l problem.hs
[1 of 1] Compiling Main             ( problem.hs, interpreted )
Ok, modules loaded: Main.
*Main> test Empty == []
True
*Main>

为什么当 == 检查在源文件中时出现错误,但在交互式提示中却没有?

只需用类型明确注释它:

value = test Empty == ([] :: [[Int]])

[] 的类型可以是任何类型:[Int][Float][[Int]]。编译器无法弄清楚,因为即使 Exp 也是多态的。如果你的函数是这样的,你就不必显式注释:

test :: EXP Int -> [[Int]]
test Empty = []
test (Symbol x) = [[x]]

value = test Empty == []

或者即使您准备好像这样给它提示:

value :: [[Int]]
value = (test Empty)

value2 = value == []

也就是说,不是使用 Int,而是使用 () 进行注释,就像 @bheklir 所做的那样。这是标记类型以消除编译器歧义的更好方法。

你需要value编译的是本地类型签名

value = (test Empty :: [[()]]) == []

或者更好的是,使用 null:

value = null $ test Empty

这是因为test的类型是

test :: EXP a -> [[a]]

value 的类型就是 Bool。编译器无法准确猜测 value 内部使用的 Eq 实例,无法从上下文中推断出来。通常,无论何时看到 == [],都应将其替换为 null 函数,因为这样可以避免 Eq 约束。

它在 GHCi 中有效,因为当您输入 (test Empty) == [] 时,GHCi 的扩展默认规则将自动选择 () 作为不明确的 a 类型。