我正在关注this教程,该教程使用scotty和persistent来创建一个简单的API。
但是,我正在尝试使用scotty和mysql简单库创建一个简单的api。
现在我陷入了代码中的某一点。
在下面的代码中,我无法将 getUser 函数转换为输入&#34; ActionT错误配置&#34; ,因为我的代码失败了。< / p>
任何人都可以帮助我理解如何转换getUser函数以实现所需的类型签名吗?
代码
type Error = Text
type Action = ActionT Error ConfigM ()
config :: Config
config = Config
{ environment = Development
,db1Conn = connect connectionInfo
}
main :: IO ()
main = do
runApplication config
runApplication :: Config -> IO ()
runApplication c = do
o <- getOptions (environment c)
let r m = runReaderT (runConfigM m) c
scottyOptsT o r application
application :: ScottyT Error ConfigM ()
application = do
e <- lift (asks environment)
get "/user" getTasksA
getTasksA :: Action
getTasksA = do
u <- getUser
json u
getUser :: IO User
getUser = do
e <- asks environment
conn <- db1Conn config
[user]<- query_ conn "select login as userId, email as userEmail from member limit 1"
return user
错误
• Couldn't match type ‘IO’ with ‘ActionT Error ConfigM’
Expected type: ActionT Error ConfigM User
Actual type: IO User
• In a stmt of a 'do' block: u <- getUser
In the expression:
do { u <- getUser;
json u }
In an equation for ‘getTasksA’:
getTasksA
= do { u <- getUser;
json u }
答案 0 :(得分:2)
您遗漏了大量代码(导入和编译指示以及User
的定义,请在下次加入 - 请参阅MCVE。
但现在问你的问题:
我会将Action
类型更改为以下
type Action a = ActionT Error ConfigM a
然后getTasksA
具有以下类型签名
getTasksA :: Action ()
getTasksA = do
u <- getUser
json u
(或者您可以将其写为getTasksA = getUser >>= json
)
和getUser
getUser :: Action User
getUser = do
e <- asks environment
conn <- db1Conn config
[user] <- liftIO $ query_ conn "select login as userId, ..."
return user
[user] <- liftIO $ query ..
是一个坏主意 - 如果找不到用户会导致应用程序崩溃 - 尝试编写总函数和模式匹配。最好返回Maybe User
。
getUser :: Action (Maybe User)
getUser = do
e <- asks environment
conn <- db1Conn config
fmap listToMaybe . liftIO $ query_ conn "select login as userId, ..."
如果你能绕过它,而不是使用persistent
而不是手工编写SQL查询 - 这很容易出错,特别是在重构时,想象一下将userId
重命名为{ {1}}。
您userID
几次ask
但不使用它。使用environment
或甚至-Wall
进行编译以获取警告甚至提升警告以编译错误(这对于生产设置来说是个好主意。