代码之家  ›  专栏  ›  技术社区  ›  keithb

当代码中没有可见的列表时,[String]为什么是推断类型?

  •  2
  • keithb  · 技术社区  · 15 年前

    我做了个测试:

    testReadFile = runTestTT $ TestLabel "InteractionDomain.readFileContentsToList" (TestList [
        (TestLabel "testing infrastructure: read test file" (TestList [
            TestCase (withTempFileContainingText (\fileHandle ->
                assertEqual "contents as expected" "The dog barks at midnight." (do 
                    content <- hGetContents fileHandle
                    return content)))]))])
    

    withTempFileContainingText

    withTempFileContainingText lambda = 
            bracketOnError 
                (do (path, fileHandle) <- openTempFile "." "input.txt"
                    return fileHandle)
                (deleteFile)
                (\fileHandle -> do 
                    hPutStr fileHandle "The dog barks at midnight."
                    hClose fileHandle --hoping this flushes buffers
                    return (lambda fileHandle))
    

    ghc 抱怨说

    InteractionDomain.hs:36:4:
        Couldn't match expected type `IO String'
               against inferred type `[String]'
        In a stmt of a 'do' expression: content ≤- hGetContents fileHandle
    

    我不明白。为什么会有这样的推论 content

    3 回复  |  直到 15 年前
        1
  •  4
  •   J Cooper    15 年前

    好吧,我现在看到的是你断言中的类型不匹配。

    资产等价物 String -> a -> a -> Assertion String 作为第二个论点,意思是 字符串 也应该是第三个论点。然而,你的 do 表达式不返回 字符串 ,但是 IO String

    编辑:一旦你搞砸了 IO <- ,然后立即将其包装回 木卫一 具有 return . 如果你想使用这个字符串,你必须在里面做 木卫一

    do
      contents <- hGetContents handle
      assertEqual "They're equal" "Expected string" contents
    

    请注意 会回来的 IO Assertion

        2
  •  3
  •   kennytm    15 年前

    assertEqual

    assertEqual :: String -> a -> a -> Assertion
    

    从第二个论点开始 "The dog barks at midnight." 是一根弦,我们知道 a 必须是 String

    do 
      content <- hGetContents fileHandle
      return content
    

    必须返回字符串。但是String=[Char],因此Haskell会将其视为列表单子。我不知道为什么它会推断出一个[String]而不是[Char]=String,但这至少解释了列表的来源。


    顺便说一句,断言已经是IO()。如果你 return 您将得到一个IO(IO())的断言。也许你是说

    withTempFileContainingText :: (Handle -> IO c) -> IO c
    withTempFileContainingText lambda = 
        bracketOnError 
            (return . snd =<< openTempFile "." "input.txt")
            (deleteFile)
            (\fileHandle -> do
                hPutStr fileHandle "The dog barks at midnight."
                hClose fileHandle
                lambda fileHandle)   -- # <--- No return here
    

    testCase 可以写成

    testCase :: Assertion
    testCase = withTempFileContainingText $ \fileHandle -> do
        conts <- hGetContents fileHandle
        assertEqual "contents as expected" "The dog barks at midnight." conts
        -- # ^-- No return here.
    
        3
  •  0
  •   keithb    15 年前

    谢谢大家的宝贵指点。

    它运行并通过:

    withTempFileContainingText lambda = 
            bracketOnError 
                (openTempFile "." "input.txt")
                (\(filePath, fileHandle) -> do
                    removeFile filePath)
                (\(filePath, fileHandle) -> do
                    startOfFile <- hGetPosn fileHandle 
                    hPutStr fileHandle "The dog barks at midnight."
                    hFlush fileHandle
                    hSetPosn startOfFile
                    lambda fileHandle
                    removeFile filePath)
    
    
    testReadFile = runTestTT $ TestLabel "InteractionDomain.readFileContentsToList" (TestList [
        (TestLabel "testing infrastructure: read test file" (TestList [
            TestCase (withTempFileContainingText (\fileHandle -> do
                content <- hGetContents fileHandle 
                assertEqual "contents as expected" "The dog barks at midnight." content))]))])