5

我正在尝试使用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)

我为每个函数设置了类型,但没有解决问题。

您知道这种类型的歧义从何而来以及如何消除它?

4

2 回答 2

6

快速修复:

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.

现在,问题Settings在于该m参数仅存complete在于具有 type 的字段中CompletionFunc m。但是在我们的示例中,我们忽略了旧complete字段,而只是将其替换为新字段。因此,据 GHC 所知,旧complete字段可能是任何类型的。并且由于旧complete字段是我们可能从中获得有关 的m参数信息的唯一来源defaultSettings,并且我们完全不受约束,因此 GHC 无法推断这m是 a MonadIO

如果我们添加(defaultSettings :: Settings IO),那么旧m参数将被实例化,IO不再有问题。请注意, m参数与旧参数完全无关m,因为我们只是忽略了旧complete字段并将其替换为新函数。新m参数IO由顶层mySettings :: Settings IO注解确定。

事实上,我们可以defaultSettings用任何MonadIO类型实例化,结果都是一样的。同样,这是因为我们忽略了 的旧值complete

于 2015-04-01T13:43:25.950 回答
3

的类型Settings有点多态。请注意,haskline作者意识到了这个可能的问题,并提供了一个setComplete函数来避免这个特殊问题。正如其他答案所示,手动指定类型也是一种选择。

于 2015-04-01T15:16:20.077 回答