Haskell 中的奇怪返回

发布于 2024-11-29 13:45:34 字数 522 浏览 1 评论 0原文

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

It checks for a element in the string by looking at "n"(so if n = 2 it will check if the second string in the list) then see if it exists. If it does exist it will return the original string list, if not it will error.Why does it do this? :

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

﹏半生如梦愿梦如真 2024-12-06 13:45:34

doesFileExist的类型是String -> IO布尔。如果你的程序想要知道一个文件是否存在,它必须与文件系统交互,这是一个 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"

The type of doesFileExist is String -> IO Bool. If your program wants to know whether a file exists, it has to interact with the file system, which is an IO action. If you want your checkString function to do that, it will also have to have some kind of IO-based type. For example, I think something like this would work, though I haven't tried it:

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"
幽梦紫曦~ 2024-12-06 13:45:34

对 MatrixFrog 在他的回答中提到的内容进行补充。如果您查看函数签名,即 [String] ->整数-> [String] 它表明该函数是一个纯函数,不涉及任何副作用,在函数体中,您使用的是 doesFileExist ,其签名为 字符串 -> IO Bool 其中 IO 的存在表明它是一个不纯的函数,即它涉及一些 IO。在haskell中,不纯函数和纯函数之间有严格的分离,事实上,如果你的函数调用了比你的函数不纯的其他函数,那么它也是不纯的。因此,在您的情况下,您的函数 checkString 需要是不纯的,这可以通过使其返回 IO [String] 来完成,这就是 MatrixFrog 在他的答案中提到的。

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

To add to what MatrixFrog has mentioned in his answer. If you look at your function signature i.e [String] -> Int -> [String] it indicates that this function is a pure function and doesn't involved any side effects, where as in your function body you are using doesFileExist which has a signature of String -> IO Bool where the presence of IO indicates it is a impure function i.e it involves some IO. In haskell there is a strict separation between impure and pure functions and as a matter of fact if your function calls some other function which is impure than your function is also impure. So in your case your function checkString needs to be impure and that can be done by making it return IO [String], which is what MatrixFrog has mentioned in his answer.

On another note, I would suggest that you can make the function to be something like:
checkString :: String -> IO (Maybe String) ,as your function doesn't need the whole list of string as it just need a specific string from the list to do its work and rather than throwing an error you can use Maybe to detect the error.
This is just a suggestion but it also depends on how your function is being used.

昔日梦未散 2024-12-06 13:45:34

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

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

在列表 monad 的情况下,return 只是返回单例列表,因此您

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

会得到类似的行为(我个人的观点是,如果 GHC 有一个打印出可能导致类型错误的常见错误的选项;我对提问者表示同情,因为我收到了很多需要时间才能弄清楚的类型错误消息)。

I think the problem is that your type signature forces the do block to assume that it is some other monad. For example, suppose you're working in the list monad. Then, you could write

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

In the case of the list monad, the return simply returns the singleton list, so you get behavior like,

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

(My personal opinion is that it would be very helpful if the GHC had an option to print out common mistakes that could cause a type error; I sympathize with the asker in that I've gotten a lot of type error messages that take time to figure out).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文