Dacto
Dacto

Reputation: 2911

Using mapM f [list] where f is defined with do notation

I currently have this code which will perform the main' function on each of the filenames in the list files.

Ideally I have been trying to combine main and main' but I haven't made much progress. Is there a better way to simplify this or will I need to keep them separate?

{- Start here -}
main :: IO [()]
main = do
    files <- getArgs
    mapM main' files

{- Main's helper function -}
main' :: FilePath -> IO ()
main' file = do 
    contents <- readFile file
    case (runParser parser 0 file $ lexer contents) of Left err -> print err
                                                       Right xs -> putStr xs

Thanks!

Edit: As most of you are suggesting; I was trying a lambda abstraction for this but wasn't getting it right. - Should've specified this above. With the examples I see this better.

Upvotes: 1

Views: 152

Answers (2)

shang
shang

Reputation: 24832

The Control.Monad library defines the function forM which is mapM is reverse arguments. That makes it easier to use in your situation, i.e.

main :: IO ()
main = do
    files <- getArgs
    forM_ files $ \file -> do
        contents <- readFile file
        case (runParser f 0 file $ lexer contents) of
            Left err -> print err   
            Right xs -> putStr xs

The version with the underscore at the end of the name is used when you are not interested in the resulting list (like in this case), so main can simply have the type IO (). (mapM has a similar variant called mapM_).

Upvotes: 6

Roman Cheplyaka
Roman Cheplyaka

Reputation: 38758

You can use forM, which equals flip mapM, i.e. mapM with its arguments flipped, like this:

forM_ files $ \file -> do
  contents <- readFile file
  ...

Also notice that I used forM_ instead of forM. This is more efficient when you are not interested in the result of the computation.

Upvotes: 5

Related Questions