我有这个测试:
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
是一个字符串列表?这段代码应该是什么样的?
答案 0 :(得分:4)
嗯,我马上看到的是你断言中的类型不匹配。
assertEqual是String -> a -> a -> Assertion
。您传递String
作为第二个参数,这意味着String
也应该是第三个参数。但是,您的do
表达式不会返回String
,而是返回IO String
。
编辑:要扩展,一旦你弄乱IO
,你就不能放弃它。您使用<-
正确地从IO中提取了值,但随后立即将其重新包装到IO
return
。如果要使用该字符串,则必须在IO
内进行,例如:
do
contents <- hGetContents handle
assertEqual "They're equal" "Expected string" contents
请注意,您do
将返回IO Assertion
。如果要使用断言值,则需要以类似方式展开它,依此类推。 Haskell不会让你逃避(隐藏)副作用!
答案 1 :(得分:3)
assertEqual
的类型是
assertEqual :: String -> a -> a -> Assertion
由于第二个参数“"The dog barks at midnight."
”是一个字符串,我们知道a
必须是String
。因此do表达式
do
content <- hGetContents fileHandle
return content
必须返回一个String。但是String = [Char],因此Haskell会将其视为List monad。我不知道为什么它推断[String]而不是[Char] = String,但这至少解释了List的来源。
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.
答案 2 :(得分:0)
感谢所有人提供了一些有价值的建议。
这会运行并通过:
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))]))])