2011-08-15 104 views
3
checkstring :: [String] -> Int -> [String] 
checkstring p n = do z <- doesFileExist (p !! n) 
    if z 
    then p 
    else error $ "'" ++ (p !! n) ++ "' file path does not exist" 

它通过查看“n”(因此如果n = 2,它将检查列表中的第二个字符串是否存在)来检查字符串中的元素。如果它确实存在,它将返回原始字符串列表,如果不存在,它将会出错。为什么它会这样做? :Haskell怪异返回

Couldn't match expected type `[t0]' with actual type `IO Bool' 
    In the return type of a call of `doesFileExist' 
    In a stmt of a 'do' expression: z <- doesFileExist (p !! n) 
+0

请参阅http://stackoverflow.com/questions/6904169/managing-the-io-monad上的答案和讨论 – MatrixFrog

回答

6

doesFileExist的类型是String -> IO Bool。如果你的程序想知道文件是否存在,它必须与文件系统交互,这是一个IO动作。如果你想让你的checkString函数来做到这一点,它也必须有某种基于IO的类型。举例来说,我觉得像这样的工作,虽然我还没有尝试过:

checkstring :: [String] -> Int -> IO [String] 
checkstring p n = do z <- doesFileExist (p !! n) 
    if z 
    then return p 
    else error $ "'" ++ (p !! n) ++ "' file path does not exist" 
+0

如何将其更改为基于IO的类型?编辑为 – ArchHaskeller

+0

以包含示例 – MatrixFrog

0

我认为问题是,你的类型的签名迫使do块假设它是一些其他的单子。例如,假设你在列表monad中工作。然后,你可以写

myFcn :: [String] -> Int -> [String] 
myFcn p n = do 
    return (p !! n) 

在列表单子的情况下,return简单地返回单一列表,所以你得到的行为像,

> myFcn ["a", "bc", "d"] 1 
["bc"] 

(我个人的看法是,这将是如果GHC有一个选项可以打印出可能导致类型错误的常见错误,那么这非常有帮助;我同情提问者,因为我收到了很多类型错误消息,需要时间才能找出答案)。

2

添加到MatrixFrog在他的答案中提到的内容。如果你看看你的功能签名,即[String] -> Int -> [String]它表明这个功能是一个纯功能,并且不涉及任何副作用,在你使用的功能体中doesFileExist的签名为String -> IO Bool,其中IO的出现表示它是一个不纯的功能,即它涉及一些IO。在haskell中,不纯和纯函数之间存在严格的分离,事实上,如果你的函数调用某个不纯净的函数,那么这个函数也是不纯的。所以在你的情况下,你的功能checkString需要不纯,可以通过返回IO [String]来完成,这是MatrixFrog在他的回答中提到的。

在另一方面,我建议你可以做的功能是这样的:
checkString :: String -> IO (Maybe String),为你的功能并不需要串的整个列表,因为它需要的只是一个特定的字符串从列表中做它的工作,而不是抛出一个错误,你可以使用Maybe来检测错误。 这只是一个建议,但它也取决于你的功能如何使用。