【发布时间】:2015-04-05 04:18:26
【问题描述】:
我正在使用 scotty 和 persistent 在 Haskell 服务器上工作。许多处理程序需要访问数据库连接池,所以我开始在整个应用程序中传递连接池,以这种方式:
main = do
runNoLoggingT $ withSqlitePool ":memory:" 10 $ \pool ->
liftIO $ scotty 7000 (app pool)
app pool = do
get "/people" $ do
people <- liftIO $ runSqlPool getPeople pool
renderPeople people
get "/foods" $ do
food <- liftIO $ runSqlPool getFoods pool
renderFoods food
其中getPeople 和getFoods 是适当的persistent 数据库操作,它们分别返回[Person] 和[Food]。
在池上调用 liftIO 和 runSqlPool 的模式会在一段时间后变得令人厌烦 - 如果我可以将它们重构为一个函数,就像 Yesod 的 runDB 一样,那不是很好,它只需要查询并返回适当的类型。我尝试写这样的东西是:
runDB' :: (MonadIO m) => ConnectionPool -> SqlPersistT IO a -> m a
runDB' pool q = liftIO $ runSqlPool q pool
现在,我可以这样写了:
main = do
runNoLoggingT $ withSqlitePool ":memory:" 10 $ \pool ->
liftIO $ scotty 7000 $ app (runDB' pool)
app runDB = do
get "/people" $ do
people <- runDB getPeople
renderPeople people
get "/foods" $ do
food <- runDB getFoods
renderFoods food
GHC 抱怨的除外:
Couldn't match type `Food' with `Person'
Expected type: persistent-2.1.1.4:Database.Persist.Sql.Types.SqlPersistT
IO
[persistent-2.1.1.4:Database.Persist.Class.PersistEntity.Entity
Person]
Actual type: persistent-2.1.1.4:Database.Persist.Sql.Types.SqlPersistT
IO
[persistent-2.1.1.4:Database.Persist.Class.PersistEntity.Entity
Food]
In the first argument of `runDB', namely `getFoods'
GHC 似乎在说实际上runDB 的类型以某种方式变得专业化了。但是像runSqlPool 这样的函数是如何定义的呢?它的类型签名看起来和我的很像:
runSqlPool :: MonadBaseControl IO m => SqlPersistT m a -> Pool Connection -> m a
但它可以与返回许多不同类型的数据库查询一起使用,就像我最初所做的那样。我认为我在这里对类型有一些基本的误解,但我不知道如何找出它是什么!任何帮助将不胜感激。
编辑:
根据 Yuras 的建议,我添加了以下内容:
type DBRunner m a = (MonadIO m) => SqlPersistT IO a -> m a
runDB' :: ConnectionPool -> DBRunner m a
app :: forall a. DBRunner ActionM a -> ScottyM ()
typedef 需要 -XRankNTypes。但是,编译器错误仍然相同。
编辑:
评论员的胜利。这允许代码编译:
app :: (forall a. DBRunner ActionM a) -> ScottyM ()
对此我很感激,但仍然感到困惑!
【问题讨论】:
-
尝试使用明确的
forall将类型签名添加到app,您很可能会看到问题所在。 -
@Yuras 我认为这个问题的一部分是我目前对明确的
forall的理解非常差,但我会努力这样做。 -
我猜应该是
app :: (forall a. DBRunner ActionM a) -> ScottyM ()。 -
@TomEllis 我应该为此启用任何特定的扩展程序吗?它仍然给我同样的错误。编辑:好的,道歉 - 我让我的处理程序在不同的功能中。在那里添加类型签名并根据需要启用更多扩展(
RankNTypes和FlexibleContexts)后,我开始看到新的错误。会回来报告的。 -
你能发布你的完整代码吗?我想尝试一下,但我不想猜测你的进口是什么等等。
标签: haskell polymorphism scotty