首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >什么时候泛型函数不是泛型?

什么时候泛型函数不是泛型?
EN

Stack Overflow用户
提问于 2015-02-05 18:40:16
回答 3查看 980关注 0票数 16

我正在使用scottypersistent在Haskell服务器上工作。许多处理程序都需要访问数据库连接池,因此我采用了在整个应用程序中传递连接池的方式:

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

其中,getPeoplegetFoods是适当的persistent数据库操作,分别返回[Person][Food]

在池上调用liftIOrunSqlPool的模式在一段时间后会变得令人厌烦-如果我可以将它们重构为一个函数,如Yesod的runDB,它将只接受查询并返回适当的类型,这不是很好吗?我尝试写这样的东西是:

代码语言:javascript
运行
复制
runDB' :: (MonadIO m) => ConnectionPool -> SqlPersistT IO a -> m a
runDB' pool q = liftIO $ runSqlPool q pool

现在,我可以这样写:

代码语言:javascript
运行
复制
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抱怨:

代码语言:javascript
运行
复制
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这样的函数是如何定义的呢?它的类型签名看起来与我的相似:

代码语言:javascript
运行
复制
runSqlPool :: MonadBaseControl IO m => SqlPersistT m a -> Pool Connection -> m a

但它可以用于返回许多不同类型的数据库查询,就像我最初所做的那样。我认为我在这里对类型有一些基本的误解,但我不知道如何找出它是什么!任何帮助都将不胜感激。

编辑:

在Yuras的建议下,我添加了以下内容:

代码语言:javascript
运行
复制
type DBRunner m a = (MonadIO m) => SqlPersistT IO a -> m a
runDB' :: ConnectionPool -> DBRunner m a
app :: forall a. DBRunner ActionM a -> ScottyM ()

这需要类型定义函数的-XRankNTypes。但是,编译器错误仍然是相同的。

编辑:

评论员们胜利了。这允许代码编译:

代码语言:javascript
运行
复制
app :: (forall a. DBRunner ActionM a) -> ScottyM ()

对此我心存感激,但仍然感到困惑!

代码目前看起来像thisthis

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

https://stackoverflow.com/questions/28341784

复制
相关文章

相似问题

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