我尝试使用 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)
我为每个功能设置了类型,但它没有解决问题。
您是否知道此类歧义来自何处以及如何将其删除?
答案 0 :(得分: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
字段中,其类型为CompletionFunc m
。但在我们的示例中,我们忽略旧的complete
字段,并将其替换为新字段。因此,就GHC而言,旧的complete
字段可能是任何类型。由于旧的complete
字段是唯一可以从中获取有关m
defaultSettings
参数的信息的来源,我们完全不受约束,因此GHC无法推断那m
是MonadIO
。
如果我们添加(defaultSettings :: Settings IO)
,那么旧的m
参数会被实例化为IO
,并且不再存在问题。请注意, new m
参数与旧的m
参数完全无关,因为我们忽略了旧complete
字段并将其替换为新函数。顶级m
注释确定新的IO
参数为mySettings :: Settings IO
。
事实上,我们可以使用任何defaultSettings
类型实例化MonadIO
,结果将是相同的。同样,这是因为我们忽略了complete
的旧值。
答案 1 :(得分:3)
Settings
的类型有点太多态。请注意, haskeline 作者了解了这个可能的问题,并提供了a setComplete
function来避免此特定问题。手动指定类型也是一个选项,因为其他答案显示。