Переменная неоднозначного типа с автозаполнением Haskeline
Я пытаюсь реализовать функцию автозаполнения с 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)
Я установил тип для каждой функции, но это не решило проблему.
У вас есть идея, откуда возникает эта неясность типа и как ее устранить?
2 ответа
Быстрое исправление:
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
и больше нет проблем. Обратите внимание, что новый m
параметр совершенно не связан со старым m
параметр, потому что мы просто проигнорировали старый complete
поле и заменил его новой функцией. Новый m
параметр определяется как IO
на высшем уровне mySettings :: Settings IO
аннотаций.
На самом деле, мы могли бы создать экземпляр defaultSettings
с любым MonadIO
типа, и результат будет таким же. Опять же, это потому, что мы игнорируем старую ценность complete
,
Тип Settings
это слишком много полиморфно. Обратите внимание, что авторы haskeline знали об этой возможной проблеме и предоставили setComplete
Функция, чтобы избежать этой конкретной проблемы. Указание типа вручную также возможно, как показывают другие ответы.