tags:

views:

208

answers:

4

For example:

newfile :: FilePath -> IO Bool
newfile x | length x <= 0 = return False
          | doesFileExist x == True = return False
          | otherwise = return True

Can this be made to work?

+4  A: 

No, there's no way to do this (short of unsafe tricks which would be completely inappropriate here).

BTW doesFileExist x == True would be better written as doesFileExist x were it possible at all.

Ganesh Sittampalam
+8  A: 

You're already in the IO monad, so why not use the following?

newfile :: FilePath -> IO Bool
newfile x | length x <= 0 = return False
          | otherwise = do exists <- doesFileExist x
                           return $ not exists

For applicative goodness:

import Control.Applicative

newfile :: FilePath -> IO Bool
newfile x | length x <= 0 = return False
          | otherwise = not <$> doesFileExist x

As you can see, the applicative route is even more concise than the guards you'd like to use in your question!

Greg Bacon
+1  A: 

The type of guard clauses must be Bool. The type of doesFileExist x is IO Bool. The type mismatch means you can't do that.

Justice
This doesn't really mean anything. The type of `getLine` is `IO String`. The type of `(++ "foo")` is `String -> String`. But you can still feed `getLine` into `(++ "foo")` with the right combinators. (Namely `(++ "foo") <$> getLine` instead of `(++ "foo") $ getLine`. So the answer to this question is not as simple as your post may lead someone to believe. (I think the word "No." would be more correct than your post, actually.)
jrockway
I'm not sure I understand your point. I'm not sure how you expect to get a `Bool` out of an `IO Bool` using combinators. While you can use `unsafePerformIO` to get a `Bool` out of an `IO Bool`, please don't. Other than that, guard clauses require `Bool` expressions, and not an expression of any other type. So what did I miss? How is the single word "No" more correct, rather than an explanation of what is the expected type and what was the given type?
Justice
A: 

This works and does what's needed:

newfile :: FilePath -> IO Bool
newfile fn = do 
    x <- runErrorT $ do
        when ((length fn) <= 0) (throwError "Empty filename")
        dfe <- liftIO $ doesFileExist fn
        when (dfe) (throwError "File does not exist")
        return True
    return $ either (\_ -> False) id x
me2
`\\_ -> False` can be written `const False`. Stylistically, I believe the latter carries the intent better, but it's effectively equivalent.
ephemient