Haskell声明RunDB类型报Not in scope: type variable ‘m’ 问题求助
错误原因
你遇到的编译错误本质是未绑定的自由类型变量:
- Haskell的普通类型别名定义中,所有出现在类型体里的类型变量要么显式声明为类型别名的参数,要么被
forall显式量化,否则会被识别为未定义的变量。 - 你代码里的
m只出现在约束MonadIO m里,没有被forall绑定也没有作为类型别名的参数,因此编译器报错Not in scope: type variable ‘m’。
修复方案
有两种常用修复方式,根据你的业务需求选择即可:
方案1:将m声明为类型别名的参数
如果需要在不同场景下给RunDB指定具体的Monad类型(比如有的地方用ActionM,有的地方用普通IO),可以把m设为类型参数:
-- 类型别名声明增加m参数 type RunDB m = MonadIO m => (forall a. SqlPersistT IO a -> m a) -- 对应的函数签名也要补充m的约束 runDB' :: MonadIO m => ConnectionPool -> RunDB m runDB' pool q = liftIO $ runSqlPool q pool
不需要额外开启其他语言扩展,你已经开启的RankNTypes足够支持这个写法。
方案2:显式量化m,把RunDB定义为高阶多态类型
如果你希望RunDB本身就是一个可以适配任意MonadIO的通用函数类型,不需要额外传类型参数,可以把forall m加到类型定义最前面:
-- 显式量化m,将其纳入类型的作用域 type RunDB = forall m. MonadIO m => (forall a. SqlPersistT IO a -> m a) -- 函数签名可以直接用原来的写法,不需要修改 runDB' :: ConnectionPool -> RunDB runDB' pool q = liftIO $ runSqlPool q pool
这个写法仍然只需要你已经开启的RankNTypes扩展即可正常编译。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

