Home > front end >  Monad Transformer with recursion
Monad Transformer with recursion

Time:05-14

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 | ...
             | ...
  • Related