when I want to load a bmp file I do this with:
loadBMP :: String -> IO Picture
If it isn't certain if the given path exists one could do something as follows:
saveLoad :: String -> IO Picture
saveLoad str = do
b <- doesFileExist str
if b then loadBMP str
else return Blank
Another way could also be; to use monad transformer:
saveLoadM :: String -> MaybeT IO Picture
saveLoadM s = do
b <- lift $ doesFileExist s
if b then do
p <- lift$ loadBMP s
return p
else MaybeT $ return Nothing
But how would you deal with a list of files?
test ::[String] -> ListT IO Picture
test [] = ListT $ return []
test (x:xs) = do
b <- lift $ doesFileExist x
if b then do
p <- lift$ loadBMP x
return p -- would yield a simple [p]
-- therefore:
p : test xs -- wrong -> not working
else test xs
CodePudding user response:
You can use the witherable
package, like this:
import Witherable
test :: [String] -> IO [Picture]
test = wither $ \x -> do
b <- doesFileExist x
if b then do
p <- loadBMP x
return $ Just p
else return Nothing
To get a sense of intuition for what wither
means, imagine if it were named mapMaybeM
instead.
CodePudding user response:
You just need to fmap
.
test :: [String] -> IO [Picture]
-- this bit as before...
if b then do
p <- loadBMP x
(p:) <$> test xs
else test xs
But you should not use doesFileExist
this way. Instead, load the bitmap and catch the exception when the file does not exist; this prevents a race condition.
test (x:xs) = do
imgE <- try (loadBMP x)
case imgE of
Right img -> (img:) <$> test xs
Left err | isDoesNotExistError err -> test xs
| otherwise -> throwIO err -- reraise other exceptions
If you're okay with extensions, I feel an anonymous case would fit well here.
test (x:xs) = try (loadBMP x) >>= \case
Right img -> ...
Left err | ...
| ...