首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Haskell scotty对IO的行动

Haskell scotty对IO的行动
EN

Stack Overflow用户
提问于 2020-08-01 14:24:37
回答 1查看 377关注 0票数 1

我又回到了努力学习Haskell和,哦,孩子,这是困难的!我试图在Scotty端点中做一个简单的mongoDB插入。问题是insert函数的类型返回在Scotty语句中不被接受。这个程序非常简单:

代码语言:javascript
复制
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Data.Monoid (mconcat)
import Control.Monad.Trans(liftIO,lift,MonadIO)
import System.IO
import Data.Text.Lazy.Encoding (decodeUtf8)
import Data.Text.Lazy (pack,unpack)
import Data.Maybe
import Data.Time.Clock.POSIX
import Database.MongoDB    (Action, Document, Document, Value, access,
                            allCollections,insert, close, connect, delete, exclude, find,
                            host,findOne, insertMany, master, project, rest,
                            select, liftDB, sort, Val, at, (=:))

main :: IO ()
main = scotty 3000 $ do

    post "/logs" $ do
       id <- liftIO $ getTimeInMillis
       b <- body
       let decodedBody = unpack(decodeUtf8 b)
       i <- liftIO $ insertLog id decodedBody
       text $ "Ok"

--setup database connection
run::MonadIO m => Action m a -> m a 
run action = do
        pipe <- liftIO(connect $ host "127.0.0.1")
        access pipe master "data" action

getTimeInMillis ::Integral b => IO b
getTimeInMillis = round `fmap` getPOSIXTime

insertLog::MonadIO m => Int -> String -> Action m Value
insertLog id body = run $ insert "logs" ["id" =: id, "content" =: body]

问题就在这条线上

代码语言:javascript
复制
 i <- liftIO $ insertLog id decodedBody

类型错误是

代码语言:javascript
复制
 Expected type: Web.Scotty.Internal.Types.ActionT
                       Data.Text.Internal.Lazy.Text IO Value
 Actual type: Action m0 Value

欢迎任何帮助或建议!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-01 15:21:47

我看到了一条不同的错误信息。也许您做了一些更改(比如添加liftIO)。

代码语言:javascript
复制
• 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

在队伍中:

代码语言:javascript
复制
i <- liftIO $ insertLog id decodedBody

liftIO函数需要一个真正的IO操作,某些a的类型为IO a。但是,表达式insertLog id decodedBody并不表示IO操作。对于具有Action m Value约束的某些m来说,是MonadIO类型的Mongo操作。您需要在Action中使用一些函数运行Mongo的IO值。看起来您已经编写了这样一个函数,名为run。它是为通用MonadIO m编写的,但可以专门用于:

代码语言:javascript
复制
run :: Action IO a -> IO a

因此,如果您首先运行Mongo操作(将其转换为IO),然后解除该操作(在post下的Scotty操作中运行该操作),则应键入下列命令:

代码语言:javascript
复制
i <- liftIO $ run $ insertLog id decodedBody

更新:喔!我错过了run函数中的insertLog。你要么想写:

代码语言:javascript
复制
-- 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]

您想要写:

代码语言:javascript
复制
-- 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]

这将避免双run问题。

run没有按照原来代码的意图工作的原因有点复杂.

问题是,run具有灵活性,可以通过为任何支持MonadIO mm返回m a,从而将其Mongo操作转换为许多可能的monads。因为您为insertLog提供了一个类型签名,返回类型为MonadIO m' => Action m' Value (在这里,我更改了变量以保持mm'不同),所以类型检查器将run的返回类型与返回类型insertLog相匹配。

代码语言:javascript
复制
m a ~ Action m' Value

通过设置a ~ Valuem ~ Action m'。因此,run in insertLog实际上是与以下奇怪类型一起使用的:

代码语言:javascript
复制
run :: Action (Action m') Value -> Action m' Value

通常,这会导致类型错误,但是insert的类型也是灵活的。它没有返回Action IO Value类型的操作(这将是“通常”类型),而是高兴地调整自己,返回Action (Action IO) Value类型的操作,以匹配run所期望的操作。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63206279

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档