不明确的类型变量,但不是在ghci?

Dav*_*ric 6 haskell

任何人都可以解释为什么haskell在以下示例中强制执行显式类型签名以及如何修改它以避免需要显式声明?

import qualified Data.List as L

main = do
    print $ length $ L.nub [1,1,2,3]  -- 3, passed (Eq a, Num a) => [a]
    print $ length $ L.nub []         -- ambiguous type error, passed (Eq a) => [a]
    -- can help type system with explicit signature but how to avoid ?
    print $ length $ L.nub ([] :: [Int])
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,在ghci中以交互方式编写的相同代码没有歧义问题,并且打印零长度:

?> :m +Data.List
?> print $ length $ nub []
0  -- ?? can you explain ??
Run Code Online (Sandbox Code Playgroud)

更新: 看起来甚至同样限制Data.List.nub长度函数不会停止关于模糊类型的投诉:

length' :: Eq a => [a] -> Int
length' [] = 0
length' (x:xs) = 1 + length' xs

main = do
    print $ length' $ nub []
-- No instance for (Eq a0) arising from a use of ‘length'’
-- The type variable ‘a0’ is ambiguous
Run Code Online (Sandbox Code Playgroud)

Sho*_*hoe 10

问题是[]具有多态类型(Eq a) => [a].由于length不添加任何特定约束.

具体的类型length是:

length :: [a] -> Int
Run Code Online (Sandbox Code Playgroud)

这比nub以下更宽松:

nub :: Eq a => [a] -> [a]
Run Code Online (Sandbox Code Playgroud)

编译器需要使用length那里的特定实例,并且无法推断出类型a.

现在您有两个选择:

  1. 在文件的开头打开ExtendedDefaultRules扩展名{-# LANGUAGE ExtendedDefaultRules #-}.
  2. 明确: ... L.nub ([] :: [Int])

我建议默认使用第二个,除非你完全理解第一个的结果.

  • @DavidUnric泛型类型足以计算列表的长度,这就是标准长度函数没有Eq约束的原因!当您将Eq约束添加到您的版本时,您*具体声明*到GHC它需要提供一个Eq实例才能调用该函数.如果不知道什么类型的`a`(或传递某种具有约束的smae类型),它就无法做到这一点.它假定你的意思是你所说的,而不是查看"length"的定义,看你没有'真的'需要实例,所以它出错了. (2认同)