Переменная неоднозначного типа Haskell — я заблудился?

#haskell #mongodb

#haskell #mongodb

Вопрос:

Итак, идея в том, что я бы взял следующий код, используемый для выполнения запросов MongoDB в haskell

И я хотел бы превратить это в это, чтобы я мог притвориться, что функция run является «db», как в обычном драйвере mongo.

 db <- connectDb "127.0.0.1" "testdb" 
db $ delete $ select [] "mycollection"
  

Вот функция, которую я написал для этого:

 mdb :: (MonadIO m) => String -> String -> IO (Action m a -> m (Either Failure a))
mdb hostname dbname = do
    pipe <- runIOE $ connect $ host hostname
    return (access pipe master (pack dbname))
  

Я получил тип, оставив его нетипизированным, а затем спросил ghci, что это за тип. Я едва понимаю это.

Итак, вот вопрос

Когда я создаю в своей программе ТОЛЬКО db <- connectDb "127.0.0.1" "testdb" и не использую ее, она завершается с ошибкой неоднозначного типа: https://gist.github.com/1337864 — Как я могу сделать это недвусмысленным? Разве это плохая идея — создать такую абстракцию? Как бы вы это сделали?

Ответ №1:

Мне всегда хочется ответить на эти вопросы: «Это потому, что ваш тип неоднозначен». Например, если вам было присвоено значение:

 MonadIO m => (Action m a -> m (Either Failure a))
  

И сказали, что монада m — это конкретная монада (а не просто какая-то одна), можете ли вы сказать, какая это? Нет.

Если вы не используете возвращаемое значение в контексте, который делает очевидным, к какой монаде m принадлежит, тогда вам нужно предоставить компилятору дополнительную информацию:

 db <- connectDB "127.0.0.1" "testdb" :: IO (Action IO a -> IO (Either Failure a))
  

Комментарии:

1. Спасибо! Также обратите внимание, что изменение подписи mdb тоже работает. Я не понял, что я говорил с этим типом.

2. Было бы неплохо, если MonadIO m => m бы по умолчанию IO в других неоднозначных случаях.

3. @Dan Burton: -fextended-default-rules для подобных вещей есть и соответствующая прагма. Проверьте, есть ли значения по умолчанию для MonadIO . Я думаю, что такое дефолтирование является злом — вот почему оно отключено по умолчанию. Одним из интересных примеров является значение по умолчанию Control.Applicative для IO .

4. Единственное, что делают расширенные правила по умолчанию, это добавляют () в список типов по умолчанию (так что теперь () это, Integer и Double ) и ослабляют ограничение на то, какие классы типов могут быть по умолчанию. По умолчанию нет IO . Причина, по которой это может показаться, заключается в том, что при вводе выражений в GHCi сначала будет предпринята попытка запустить его как IO a . Если это не удается, оно вычисляется и печатается как обычно. Однако это происходит только на самом внешнем уровне, поэтому любая неоднозначность Monad m => m в выражении не будет выполняться по умолчанию.