具有 Haskeline 自动完成功能的模糊类型变量
Ambiguous type variable with Haskeline auto-completion
我正在尝试使用 Haskeline 实现自动完成功能:
import System.Console.Haskeline
import System.Console.Haskeline.IO
import Data.List
mySettings :: Settings IO
mySettings = defaultSettings {
historyFile = Just "myhist"
, complete = completeWord Nothing " \t" $ return . search
}
keywords :: [String]
keywords = ["Point","Line","Circle","Sphere"]
search :: String -> [Completion]
search str = map simpleCompletion $ filter (str `isPrefixOf`) keywords
main :: IO ()
main = do
inputLine <- initializeInput mySettings
putStrLn "done"
但是这个 GHC 错误让我有点失望:
Ambiguous type variable `t0' in the constraint:
(Control.Monad.IO.Class.MonadIO t0)
arising from a use of `defaultSettings'
Probable fix: add a type signature that fixes these type variable(s)
我为每个函数都设置了类型,但并没有解决问题。
您知道这种类型歧义从何而来以及如何消除它吗?
快速修复:
mySettings :: Settings IO
mySettings = (defaultSettings :: Settings IO)
{ historyFile = Just "myhist"
, complete = completeWord Nothing " \t" $ return . search }
这个问题是一个非常罕见的极端案例,所以上面的解决方案看起来很武断或难以理解也就不足为奇了。尽管如此,我还是试着解释一下。
defaultSettings
的类型为 MonadIO m => Settings m
。它是一个 多态值 ,此类值通常会导致类型推断出现问题。通常,如果 GHC 可以从上下文中推断出多态参数,我们只能对多态值进行计算(模式匹配、场投影等)。 Settings m
可能具有完全不同的内容,具体取决于属于 m
的确切 m
和确切类型 class 方法。
现在,Settings
的问题是 m
参数仅出现在类型为 CompletionFunc m
的 complete
字段中。但在我们的示例中,我们 忽略 旧的 complete
字段,并用新字段替换它。因此,据 GHC 所知,旧的 complete
字段可能是 any 类型。由于旧的 complete
字段是我们可能获得有关 defaultSettings
的 m
参数的信息的唯一来源,并且我们让它完全不受约束,GHC 无法推断出m
是一个 MonadIO
。
如果我们添加 (defaultSettings :: Settings IO)
,那么旧的 m
参数将实例化为 IO
,并且不再有问题。注意 new m
参数与旧的 m
参数完全无关,因为我们只是忽略了旧的 complete
字段并将其替换为新功能。新的m
参数被顶层mySettings :: Settings IO
注解确定为IO
。
事实上,我们可以用任何 MonadIO
类型实例化 defaultSettings
,结果都是一样的。同样,这是因为我们忽略了 complete
的旧值。
Settings
的类型有点多态。请注意,haskeline 作者意识到了这个可能的问题,并提供了一个 a setComplete
function 来避免这个特殊问题。正如其他答案所示,手动指定类型也是一种选择。
我正在尝试使用 Haskeline 实现自动完成功能:
import System.Console.Haskeline
import System.Console.Haskeline.IO
import Data.List
mySettings :: Settings IO
mySettings = defaultSettings {
historyFile = Just "myhist"
, complete = completeWord Nothing " \t" $ return . search
}
keywords :: [String]
keywords = ["Point","Line","Circle","Sphere"]
search :: String -> [Completion]
search str = map simpleCompletion $ filter (str `isPrefixOf`) keywords
main :: IO ()
main = do
inputLine <- initializeInput mySettings
putStrLn "done"
但是这个 GHC 错误让我有点失望:
Ambiguous type variable `t0' in the constraint:
(Control.Monad.IO.Class.MonadIO t0)
arising from a use of `defaultSettings'
Probable fix: add a type signature that fixes these type variable(s)
我为每个函数都设置了类型,但并没有解决问题。
您知道这种类型歧义从何而来以及如何消除它吗?
快速修复:
mySettings :: Settings IO
mySettings = (defaultSettings :: Settings IO)
{ historyFile = Just "myhist"
, complete = completeWord Nothing " \t" $ return . search }
这个问题是一个非常罕见的极端案例,所以上面的解决方案看起来很武断或难以理解也就不足为奇了。尽管如此,我还是试着解释一下。
defaultSettings
的类型为 MonadIO m => Settings m
。它是一个 多态值 ,此类值通常会导致类型推断出现问题。通常,如果 GHC 可以从上下文中推断出多态参数,我们只能对多态值进行计算(模式匹配、场投影等)。 Settings m
可能具有完全不同的内容,具体取决于属于 m
的确切 m
和确切类型 class 方法。
现在,Settings
的问题是 m
参数仅出现在类型为 CompletionFunc m
的 complete
字段中。但在我们的示例中,我们 忽略 旧的 complete
字段,并用新字段替换它。因此,据 GHC 所知,旧的 complete
字段可能是 any 类型。由于旧的 complete
字段是我们可能获得有关 defaultSettings
的 m
参数的信息的唯一来源,并且我们让它完全不受约束,GHC 无法推断出m
是一个 MonadIO
。
如果我们添加 (defaultSettings :: Settings IO)
,那么旧的 m
参数将实例化为 IO
,并且不再有问题。注意 new m
参数与旧的 m
参数完全无关,因为我们只是忽略了旧的 complete
字段并将其替换为新功能。新的m
参数被顶层mySettings :: Settings IO
注解确定为IO
。
事实上,我们可以用任何 MonadIO
类型实例化 defaultSettings
,结果都是一样的。同样,这是因为我们忽略了 complete
的旧值。
Settings
的类型有点多态。请注意,haskeline 作者意识到了这个可能的问题,并提供了一个 a setComplete
function 来避免这个特殊问题。正如其他答案所示,手动指定类型也是一种选择。