在下面的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>
为什么在== check检查是在源文件中时出现错误,而不是在交互式提示符中出现错误?
答案 0 :(得分:4)
使value
编译所需的是本地类型签名
value = (test Empty :: [[()]]) == []
或者更好的是,使用null
:
value = null $ test Empty
这是因为test
的类型是
test :: EXP a -> [[a]]
value
的类型只是Bool
。编译器无法准确猜出Eq
内部要使用的value
实例,它无法从上下文中推断出来。通常,只要您看到== []
,就应该将其替换为null
函数,因为这样可以避免Eq
约束。
它适用于GHCi,因为当您输入(test Empty) == []
时,GHCi的扩展默认规则会自动为()
类型选择a
。
答案 1 :(得分:1)
只需使用type:
明确注释它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完成的注释。这是一种更好的标记类型方法,可以消除编译器的歧义。