Переменная неоднозначного типа с автозаполнением 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 Функция, чтобы избежать этой конкретной проблемы. Указание типа вручную также возможно, как показывают другие ответы.

Другие вопросы по тегам