Weird return in Haskell
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 r开发者_开发百科eturn type of a call of `doesFileExist'
In a stmt of a 'do' expression: z <- doesFileExist (p !! n)
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"
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).
精彩评论