Разница между прелюдией и есодом с MongoDB

Я пытаюсь заставить мой MongoDB работать в Хаскеле. Я использовал этот учебник в качестве отправной точки. Когда я выполняю эти команды в прелюдии, я получаю список коллекций:

pipe <- runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317
access pipe master <databaseName> $ auth <username> <password>
access pipe master <databaseName> allCollections

Однако, когда я пытаюсь поместить это в Yesod Handler, он не компилируется. я имею

getActivityR :: Handler Import.Value
getActivityR = do
    pipe <- runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317
    access pipe master <databaseName> $ auth <username> <password>
    access pipe master <databaseName> allCollections
    returnJson $ object ["activity" .= ("abc" :: Text)]

ReturnJson действительно только для того, чтобы сообщить мне, что я завершил метод. В конце концов он вернет список действий.

Я получаю ошибку:

Couldn't match type `IO' with `HandlerT App IO'

    Expected type: HandlerT App IO Pipe

      Actual type: IO Pipe

    In a stmt of a 'do' block:

      pipe <- runIOE

              $ connect $ Host "XXXXXX.mongolab.com" $ PortNumber 33317

Так в чем же разница между Prelude/GHCi и моим кодом Yesod, создаваемым Cabal?

1 ответ

Решение

Проблема в том, что GHCi запускает ваш код в IO монада, пока ваша функция находится в HandlerT App IO монада. Но HandlerT это монадный трансформатор над IO монада, так что вы можете использовать lift "продвигать" свой IO действие к HandlerT App IO действие. Тип лифта:

lift :: (MonadTrans t, Monad m) => m a -> t m a

В твоем случае, t должен быть HandlerT App а также m должен быть IO, Итак, правильный код выглядит так:

getActivityR :: Handler Import.Value
getActivityR = do
    pipe <- lift $ runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317
    access pipe master <databaseName> $ auth <username> <password>
    access pipe master <databaseName> allCollections
    returnJson $ object ["activity" .= ("abc" :: Text)]

Я не знаю, что ты access есть, поэтому я не могу сказать, нужен ли вам лифт там или нет.

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

pipe <- liftIO $ runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317

Если вы хотите узнать больше об этой теме, вы должны искать "монадные трансформаторы".

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