Разница между прелюдией и есодом с 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
Если вы хотите узнать больше об этой теме, вы должны искать "монадные трансформаторы".