奇怪的可能出现在元组类型中

时间:2012-01-02 22:53:33

标签: haskell

我在下面的示例代码无法使用错误进行编译:

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' 

2 个答案:

答案 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子句中qq'的循环依赖关系。 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"或其他内容。