我曾在IO单子运行的函数:编译错误,而推广功能 - 复杂的错误消息
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代码中看到了这个构造,但是无法找到它。延期?什么是刚性类型变量?
我发现错误并修复了它。在
scope
之前删除liftIO $
就足够了。但这只是尝试重新编译循环。 其中在这个错误消息中讲述了错误的地方?我发现'fn'有问题。好吧,我想了一下,猜测一下:GHC推断自上而下的类型。而从liftIO
推断,m
应该是IO
,但fn
有一般类型m
所以它是错误的。 是否有任何 haskell编译器从上到下推断? (更重要的)我可以看到GHC推断输出中的子表达式的类型吗?
感谢您阅读这个长长的问题!
只是FYI你的'范围'功能并不完全是'支架'做的。 'bracket'不仅将计算包装到资源分配/释放的“括号”中,还处理异常,即使在异常情况下也释放资源。你的'scope'函数将会退出,而不是释放资源。也许这在这种情况下并不重要,但仍然如此。 –
通用MonadIO是否可以处理异常? – demi
我认为你可以用'liftIO'管理这个。毕竟它有'IO a - > m a'类型,所有异常处理例程都有'IO'类型。你可以在这里找到所有与异常相关的函数:http://hackage.haskell.org/packages/archive/base/4.5.0.0/doc/html/Control-Exception.html –