Доступ к MongoDB из Snap

Я пытаюсь получить доступ к монго с помощью драйверов mongodb haskell (драйвер snap не работает для snap> 0,5) в соединении.

Это то, что у меня есть до сих пор:

testSplice :: Splice AppHandler
testSplice = do
  record <- liftIO $ do
    pipe <- runIOE $ connect (host "127.0.0.1") 
    results <- access pipe master "db" (find $ select [] "coll")
    close pipe
    rest result

  return $ [TextNode $ T.pack $ show $ records]

Я понимаю, что мне нужно использовать liftIO там, так как действие монго происходит внутри монады IO, и я хочу вытащить это обратно. Где мое понимание ломается, это результат компиляции этого соединения:

Couldn't match expected type `IO a0'
    with actual type `Action m0 [Database.MongoDB.Document]'

Прошу прощения за вопрос «Отправьте мне коды, пожалуйста», но я в растерянности: где я ошибаюсь и как мне заставить это работать?


person Khanzor    schedule 19.11.2011    source источник


Ответы (2)


Вот ваша функция, аннотированная сигнатурами типов. Я думаю, это проясняет, в чем заключается проблема.

testSplice :: Splice AppHandler
testSplice = do
  record <- liftIO $ do
    pipe <- runIOE $ connect (host "127.0.0.1") -- :: IO Pipe
    results <- access pipe master "db" (find $ select [] "coll")
    -- ^ :: IO (Either Failure Cursor)
    close pipe -- :: IO ()
    rest result -- :: Action m [Document]

  return $ [TextNode $ T.pack $ show $ records]

Все внутри блока «liftIO $ do» должно быть действием ввода-вывода. Последняя строчка "результат отдыха" - нет. Одним из решений является добавление к этой строке «мастер канала доступа «db»», как вы сделали с find. Другое решение состоит в том, чтобы избежать двойного вызова «канала доступа...» и заменить строку поиска следующим:

result <- access pipe master "db" (find (select [] "coll") >>= rest)

Затем замените строку «результат отдыха» на «результат возврата».

То, что Даниэль говорит о том, что строка поиска не нуждается в liftIO, верно, но в данном случае это не имеет значения, потому что у IO есть экземпляр MonadIO. Так что, вероятно, так же просто хранить все элементы liftIO в одном блоке.

person mightybyte    schedule 21.11.2011
comment
Спасибо, @mightybyte. Кажется, я просто забыл добавить return после rest result (в таком состоянии не было бы проверки типов!). bind между результатами find (Action m Cursor) и rest (Cursor -> Action m [Document]) сделали свое дело. То, что я делал неправильно, было попыткой bind rest получить Either Failure Cursor, запустив значение доступа. Спасибо еще раз! - person Khanzor; 21.11.2011

Я не эксперт по MongoDB, поэтому я не уверен на 100% (и не могу это проверить), но подозреваю, что вы поставили liftIO не в том месте. У нас есть liftIO :: MonadIO m => IO a -> m a, поэтому мы должны применять liftIO к действиям, которые на самом деле являются IO, но которые мы хотим сделать чем-то большим, чем IO. Я подозреваю, что access — это функция с возвращаемым типом больше, чем IO. Предполагая, что runIOE, close и rest на самом деле имеют типы возврата IO, мы должны сделать что-то вроде этого:

testSplice = do
    pipe <- liftIO . runIOE $ connect (host "127.0.0.1")
    results <- access pipe master "db" (find $ select [] "coll") -- note: no liftIO on this one because it's presumably already lifted
    liftIO $ close pipe
    record <- liftIO $ rest result
    return [TextNode . T.pack . show $ records]

Если некоторые из этих действий на самом деле не являются IO вещами, то вы можете удалить liftIO из них.

Как вы заметили, это можно немного почистить: любые соседние строки, начинающиеся с liftIO, можно объединить. Итак, если приведенное выше окажется правильным местом для liftIOs, то это также можно было бы записать как:

testSplice = do
    pipe <- liftIO . runIOE $ connect (host "127.0.0.1")
    results <- access pipe master "db" (find $ select [] "coll")
    liftIO $ do
        close pipe
        record <- rest result
        return [TextNode . T.pack . show $ records]

(Последний там в порядке, потому что return = liftIO . return для любой разумной реализации liftIO.)

person Daniel Wagner    schedule 19.11.2011
comment
Спасибо за ответ, Даниил :). Я понимаю, что вы здесь говорите, но результаты find находятся в IO, поэтому я не думаю, что это проблема. Я бьюсь головой о результат rest, то есть Action m [Document]. Мне просто нужна часть [Document], и я не понимаю, как я должен связать это внутри другой монады? - person Khanzor; 20.11.2011