我在下面的示例代码无法使用错误进行编译:
Occurs check: cannot construct the infinite type: p0 = Maybe p0
Expected type: PSQ.PSQ (t1, t2, (t0, [a0])) (Maybe p0)
Actual type: PSQ.PSQ (t1, t2, (t0, [a0])) p0
In the third argument of `PSQ.insert', namely `q'
In the expression: PSQ.insert test' time q
如果我将来自AppendMsg的代码作为main的一部分进行编译。如果试图使它成为一个单独的函数,它就会失败并出现奇怪的相关错误。我不太确定可能的类型来自哪里。我试图解决它,例如让time = Just (PSQ.lookup test time)
但没有快乐。我没有Data.Label /镜头试过它但也没有喜悦。即使是插入附加消息的非常简单的功能也会产生相同的错误。
这里可能有什么问题?
import Data.Time
import Data.Time.Clock.POSIX
import qualified Data.PSQueue as PSQ
import Data.Maybe
import Data.Label
import Control.Category
import Prelude hiding ((.))
test = ("192.168.1.1", 3455, (1234566, msgs))
msgs = ["aaa", "bbbb", "ccccc"]
second2 = lens (\(a,b) -> b) (\b (a,_) -> (a,b))
third3 = lens (\(a,b,c) -> c) (\c (a,b,_) -> (a,b,c))
messages = second2 . third3
append x = modify messages (x :)
newRq = do
time <- getPOSIXTime
let q = PSQ.singleton test time
return q
appendMsg a q = do
let time = PSQ.lookup test q
let test' = append a test
let q' = PSQ.insert test' time q
let q = PSQ.delete test q'
return q
--insertNewRec a q = do
-- time <- getPOSIXTime
-- let q' = PSQ.insert a time q
-- return q
main :: IO()
main = do
q <- newRq
let q' = appendMsg "first" q
print (q')
根据所有评论/答案修改了appendMsg(见下文)。它现在编译但执行以<<loop>>
结束: - (。
appendMsg :: String -> PSQ.PSQ (String, Integer, (Integer, [String])) POSIXTime -> PSQ.
PSQ (String, Integer, (Integer, [String])) POSIXTime
appendMsg a q = q
where
Just time = PSQ.lookup test q
test2 = append a test
q' = PSQ.insert test2 time q
q = PSQ.delete test q'
答案 0 :(得分:5)
除了可疑的monadic类型的appendMsg
,而不是
let time = Just (PSQ.lookup test time)
(顺便说一下。我想第二个'时间'是一个错字,实际上是'q'),你应该尝试过
let Just time = PSQ.lookup test q
我强烈建议为您的函数提供类型签名,这样GHC可以为您提供更多有用的错误消息,因为这样可以报告类型错误的位置,而不会导致类型检查失败。
修改:修订后代码中<<loop>>
的原因
appendMsg :: String -> PSQ.PSQ (String, Integer, (Integer, [String])) POSIXTime
-> PSQ.PSQ (String, Integer, (Integer, [String])) POSIXTime
appendMsg a q = q
where
Just time = PSQ.lookup test q
test2 = append a test
q' = PSQ.insert test2 time q
q = PSQ.delete test q'
是where子句中q
和q'
的循环依赖关系。 where子句(或let)中的绑定是递归的,可以任意排序,因此q
中的let x = ...
都指的是最后一行中的绑定,而不是参数 - whoops。在原始代码中,您有多个let,因此绑定不是(相互)递归的,并且绑定x
遮蔽了标识符<<loop>>
的任何先前绑定。
要打破appendMsg a q = q''
,简单和推荐的修复
q'' = PSQ.delete test q'
以及where子句appendMsg a q = PSQ.delete test q'
appendMsg a q =
let Just time = ... in
let test2 = ... in
let q' = ... in
let q = ... in q
并删除where子句的最后一行您还可以构建一个let-tower
{{1}}
但我不建议这样做。
答案 1 :(得分:4)
PSQ.lookup有一个Maybe a
返回类型,因为你传递它的密钥可能实际上不在你的PSQ中。您需要处理可能错误的代码(除非您确实崩溃,或者确定它永远不会发生)。
稍微修改Daniel Fischer的答案..
let time = case PSQ.lookup test q of
Just x -> x
Nothing -> (...)
(...)
可以是默认值,也可以是error "I am a helpful error message"
或其他内容。