Я вижу другое сообщение об ошибке с этим кодом. Возможно, вы внесли какие-то изменения (например, добавили liftIO
).
• Couldn't match type ‘Control.Monad.Trans.Reader.ReaderT
Database.MongoDB.Query.MongoContext m0 Value’
with ‘IO a0’
Expected type: IO a0
Actual type: Action m0 Value
В строке:
i <- liftIO $ insertLog id decodedBody
функция liftIO
ожидает подлинное действие IO
типа IO a
для некоторых a
. Однако выражение insertLog id decodedBody
не представляет собой действие ввода-вывода. Это действие Mon go типа Action m Value
для некоторых m
, которые имеют ограничение MonadIO
. Вам нужно использовать некоторую функцию, запускающую Mon go Action
значения в IO
. Похоже, вы уже написали такую функцию с именем run
. Он написан для общего MonadIO m
, но может быть специализирован на:
run :: Action IO a -> IO a
, поэтому, если вы сначала запустите действие Mon go (чтобы превратить его в IO
), а затем поднять это действие (чтобы запустите его в действии Скотти под post
), следующее должно ввести проверку:
i <- liftIO $ run $ insertLog id decodedBody
Обновление: Упс! Я пропустил run
в функции insertLog
. Вы либо хотите написать:
-- use "run" here
main = do
...
i <- liftIO $ run $ insertLog id decodedBody
-- but no "run" here
insertLog::MonadIO m => Int -> String -> Action m Value
insertLog id body = insert "logs" ["id" =: id, "content" =: body]
ИЛИ вы хотите написать:
-- no "run" here
main = do
...
i <- liftIO $ insertLog id decodedBody
-- change the type signature and use "run" here
insertLog :: Int -> String -> IO Value
insertLog id body = run $ insert "logs" ["id" =: id, "content" =: body]
Это позволит избежать проблемы double- run
.
Причина, по которой run
не работает так, как предполагалось в вашем исходном коде, немного сложна ...
Проблема в том, что run
имеет гибкость для преобразования своего действия Mon go во многие возможных монад, возвращая m a
для любого m
, поддерживающего MonadIO m
. Поскольку вы дали insertLog
сигнатуру типа с возвращаемым типом MonadIO m' => Action m' Value
(где я изменил переменную, чтобы m
и m'
были разными), средство проверки типов сопоставило возвращаемый тип run
с возвращаемым типом insertLog
:
m a ~ Action m' Value
, задав a ~ Value
и m ~ Action m'
. Итак, ваш run
in insertLog
фактически использовался со следующим странным типом:
run :: Action (Action m') Value -> Action m' Value
Обычно это вызвало бы ошибку типа, но тип insert
также является гибким. Вместо того, чтобы возвращать действие типа Action IO Value
, которое было бы «обычным» типом, он с радостью адаптировался, чтобы возвращать действие типа Action (Action IO) Value
, соответствующее тому, что ожидал run
.