I'm trying to implement an autocompletion function with 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"
but I am a bit disappointed by this GHC error :
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)
I set the type for each function but it didn't solve the problem.
Do you have an idea where does this type ambiguity come from and how to remove it?
A quick fix:
mySettings :: Settings IO
mySettings = (defaultSettings :: Settings IO)
{ historyFile = Just "myhist"
, complete = completeWord Nothing " \t" $ return . search }
The problem is a really rare corner case, so it's no wonder that the above solution may seem arbitrary or inscrutable. I try to explain it nevertheless.
defaultSettings
has type MonadIO m => Settings m
. It's a polymorphic value, and such values often cause hiccups in the type inference. Generally, we can only do computation (pattern matching, field projections, etc.) on polymorphic values if GHC can infer the polymorphic parameter from the context. Settings m
might have completely different content depending on the exact m
and the exact type class methods that belong to m
.
Now, the issue with Settings
is that the m
parameter is only present in the complete
field, which has type CompletionFunc m
. But in our example we ignore the old complete
field, and just replace it with a new field. Therefore, as far as GHC knows, the old complete
field could have been of any type whatsoever. And since the old complete
field is the only source from which we could possibly gain information about the m
parameter of defaultSettings
, and we left it fully unconstrained, GHC can't infer that that m
is a MonadIO
.
If we add (defaultSettings :: Settings IO)
, then the old m
parameter is instantiated to IO
and there's no issue anymore. Note that the new m
parameter is completely unrelated to the old m
parameter, because we just ignored the old complete
field and replaced it with the new function. The new m
parameter is determined to be IO
by the top-level mySettings :: Settings IO
annotation.
In fact, we could instantiate defaultSettings
with any MonadIO
type, and the result would be the same. Again, this is because we ignore the old value of complete
.
The type of Settings
is a bit too much polymorphic. Note that haskeline authors were aware of this possible problem and provided a a setComplete
function to avoid this particular problem. Specifying the type manually is also an option as other answers show.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With