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,它将检查列表中的第二个字符串是否存在)然后查看它是否存在。如果确实存在,它将返回原始字符串列表,如果不存在,则会出错。为什么要这样做?:

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)
4

3 回答 3

6

的类型doesFileExistString -> 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"
于 2011-08-15T04:41:45.000 回答
2

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

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

于 2011-08-15T10:16:49.603 回答
0

我认为问题在于您的类型签名强制该do块假定它是其他一些单子。例如,假设您正在使用 list monad。然后,你可以写

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

在 list monad 的情况下,它return只是返回单例列表,所以你会得到类似的行为,

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

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

于 2011-08-15T08:30:43.840 回答