Question

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)
Was it helpful?

Solution

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"

OTHER TIPS

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.

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top