我有一个在 IO monad 中运行的函数:
withDB :: (forall c. IConnection c => c -> IO b) -> IO b
withDB fn = bracket (connectSqlite3 "int/db.sqlite3") disconnect fn
现在我决定将它概括为在一些MonadIO m
. 我是按照以下方式进行的,bracket
用我的scope
(你知道图书馆里的一些吗?)重新发明:
scope :: MonadIO m => m a -> (a -> m b) -> (a -> m c) -> m c
scope before after action = do
x <- before
r <- action x
_ <- after x
return r
withDB :: MonadIO m => (forall c. IConnection c => c -> m b) -> m b
withDB fn = liftIO $ scope
(liftIO $ connectSqlite3 "int/db.sqlite3")
(\x -> liftIO $ disconnect x) fn
我得到了错误:
Could not deduce (m ~ IO)
from the context (MonadIO m)
bound by the type signature for
withDB :: MonadIO m => (forall c. IConnection c => c -> m b) -> m b
at src\...
'm' is a rigid type variable bound by
the signature for
withDB :: MonadIO m => (forall c. IConnection c => c -> m b) -> m b
Expected type: IO b
Actual type: m b
In the third argument of 'scope' namely 'fn'
In the second argument of '($)', namely
'scope
(liftIO $ connectSqlite3 "int/db.sqlite3")
(\x -> liftIO $ disconnect x)
fn'
现在我的问题:
m~IO是什么意思?前两行错误说明了什么?另外,我在haskell代码中看到了这个〜构造,但找不到它是什么。扩大?什么是刚性类型变量?
我发现了错误并修复了它。
liftIO $
之前删除就够了scope
。但这只是尝试重新编译循环。此错误消息中的何处说明了错误的位置?我看到'fn'有问题。好的,我想了想,有了一个猜测:GHC 从上到下推断类型。liftIO
它从使用中推断m
应该是IO
但fn
具有一般类型m
,所以它是错误的。是否有任何haskell 编译器从上到下进行推断?而且(更重要的是)我可以看到 GHC 为输出中的子表达式推断出的类型吗?
感谢您阅读这个长长的问题!