我在一个Haskell项目中遇到了一个情况,在那里我得到了错误Ambiguous type variable。
相关代码是
--- Other import statements
import qualified Model as Model
---------- HTTP Handlers
needItem db user itemName = do
Model.changeItemStatus db user itemName Model.Need
listItems db user
gotItem db user itemName = do
Model.changeItemStatus db user itemName Model.Got
listItems db user
newItem db user itemName comment count = do
Model.insertItem db user itemName comment count
listItems db user
listItems db user = do
lst <- Model.listItems db user
resOk lst
--- rest of the program这些错误都是针对insertItem和changeItemStatus的,它们都是acid-state查询函数。
insertItem db name itemName comment count = withAccount db name newItem
where item = Item { itemName = itemName, itemComment = comment, itemCount = count, itemStatus = Need }
newItem account = update' db $ NewItem account item
-- other stuff
changeItemStatus db name itemName status = withAccount db name cItem
where cItem account = withItem account itemName
(\i -> update' db $ ChangeItem account $ i { itemStatus = status})withAccount和withItem是帮助我处理数据库中的Maybe返回值的辅助函数。他们被定义为
withAccount :: MonadIO m => AcidState GoGetDB -> String -> (Account -> a) -> m (Maybe a)
withAccount db name fn = do
maybeAccount <- query' db $ AccountByName name
return $ do acct <- maybeAccount
return $ fn acct
withItem :: Account -> String -> (Item -> a) -> Maybe a
withItem account itemName fn = do
item <- getOne $ (accountItems account) @= itemName
return $ fn item好吧,现在。
我已经读过几次快乐栈速成班中的AcidState文档,但是它没有多大帮助;它们在响应生成函数中直接使用查询
Ambiguous type variable错误,除了指向query'调用iteslf之外,query'或update'的函数的具体返回类型是什么(它们的函数都是AcidState DBName -> ServerPart Response,因为它们直接生成响应)。我试图在表达式的各个部分上使用insertItem和changeItemStatus的类型签名,但每次尝试都给了我一个假设,即No instance for (MonadIO m1)的错误更严重。
我还不是一个特别擅长Haskeller的人,所以我觉得我唯一能尝试的就是在这个地方随机地撒一些return $,但是听起来不太可能真的解决这个问题,或者教我任何东西。
我试图实现的一般概念是:“对DB进行此更改,然后返回当前用户的相关元素列表(可能发生更改)”。
对于我下一步该尝试什么,或者我具体出了什么问题,有什么暗示吗?我是不是用完全错误的方式想这件事?关于这个问题,我还有其他的文件可以参考吗?
PS。我已经包含了上面所有的相关代码,但是如果您想看到完整的源代码,那就是这里和这里。
编辑:全类型错误
/home/inaimathi/projects/goget/goget.hs:31:3:
Ambiguous type variable `m2' in the constraint:
(Control.Monad.IO.Class.MonadIO m2)
arising from a use of `Model.changeItemStatus'
Probable fix: add a type signature that fixes these type variable(s)
In a stmt of a 'do' block:
Model.changeItemStatus db user itemName Model.Need
In the expression:
do { Model.changeItemStatus db user itemName Model.Need;
listItems db user }
In an equation for `needItem':
needItem db user itemName
= do { Model.changeItemStatus db user itemName Model.Need;
listItems db user }
/home/inaimathi/projects/goget/goget.hs:35:3:
Ambiguous type variable `m1' in the constraint:
(Control.Monad.IO.Class.MonadIO m1)
arising from a use of `Model.changeItemStatus'
Probable fix: add a type signature that fixes these type variable(s)
In a stmt of a 'do' block:
Model.changeItemStatus db user itemName Model.Got
In the expression:
do { Model.changeItemStatus db user itemName Model.Got;
listItems db user }
In an equation for `gotItem':
gotItem db user itemName
= do { Model.changeItemStatus db user itemName Model.Got;
listItems db user }
/home/inaimathi/projects/goget/goget.hs:39:3:
Ambiguous type variable `m0' in the constraint:
(Control.Monad.IO.Class.MonadIO m0)
arising from a use of `Model.insertItem'
Probable fix: add a type signature that fixes these type variable(s)
In a stmt of a 'do' block:
Model.insertItem db user itemName comment count
In the expression:
do { Model.insertItem db user itemName comment count;
listItems db user }
In an equation for `newItem':
newItem db user itemName comment count
= do { Model.insertItem db user itemName comment count;
listItems db user }发布于 2013-02-06 20:28:30
为您的函数编写类型签名,以捕获它们应该做的事情。在编写实现之前编写它们,然后可以使用类型签名,如果编译器知道您想要的类型,则可以从编译器获得更好的错误消息,以检查实现是否做了,或者至少有机会做您想做的事情。
让我们看看问题儿童,以及他们实际上做了什么:
从acid-state中我们使用
update' :: (UpdateEvent event, MonadIO m) => AcidState (EventState event) -> event -> m (EventResult event)为
insertItem db name itemName comment count = withAccount db name newItem
where item = Item { itemName = itemName, itemComment = comment, itemCount = count, itemStatus = Need }
newItem account = update' db $ NewItem account item现在让我们看看它会产生什么样的类型。从使用
withAccount :: MonadIO m => AcidState GoGetDB -> String -> (Account -> a) -> m (Maybe a)我们看到结果有类型
m (Maybe a)对于某些MonadIO m,a是newItem的结果类型。现在,
newItem account = update' db something所以
newItem :: MonadIO mio => Account -> mio (EventResult type_of_something)因此,insertItem的结果类型应该是
m (Maybe (mio (EventResult type_of_something)))和在
newItem db user itemName comment count = do
Model.insertItem db user itemName comment count
listItems db user编译器不知道它应该在第二行中使用哪个MonadIO mio。因此,类型变量mio是不明确的。
请注意,在那里指定类型变量仍然不会做您想做的事情。我希望您实际上希望执行update',而不仅仅是计算在执行时更新数据库的操作。
对于insertItem来说,如果它确实应该更新数据库,那么现有的withAccount是没有用的。你也许需要一些东西
withAccountM :: MonadIO m => AcidState GoGetDB -> String -> (Account -> m a) -> m (Maybe a)
withAccountM db name fn = do
maybeAccount <- query' db $ AccountByName name
case maybeAccount of
Nothing -> return Nothing
Just acct -> do
result <- fn acct
return $ Just result(没有测试,可能仍然是完全错误的)实际执行update'。
对于changItemStatus,问题和可能的修复是相似的。
https://stackoverflow.com/questions/14721720
复制相似问题