Fredrik Nylén
Fredrik Nylén

Reputation: 577

Flexible number of arguments to haskell program

I am using the System.FilePath.Find module of filemanip to recursively find all files I need to process (here I will be using just printing to console as the action to perform, in order not confuse things). Now, this code:

import System.Environment (getArgs)
import System.FilePath (FilePath)
import System.Directory (doesDirectoryExist, getDirectoryContents,doesFileExist)
import Control.Monad
import System.FilePath.Find (find,always,fileType,(==?),FileType(..),(&&?),extension)


main= do 
    [dbFile,input]<- getArgs
    files <- findFiles input
    mapM_ putStrLn files 
    return ()

searchExtension :: String
searchExtension = ".hs"

findFiles :: FilePath -> IO [String]
findFiles = find (always) ( fileType ==? RegularFile &&? extension ==? searchExtension)

works well with this call

./myprog tet .

In this case, the get argument is ignored (will be the output database file later) and the second argument is searched recursively for matching files. It also allows me to specify just a single file, which is just perfect!

BUT, I would like to be able to specify

./myprog tet path1 path2 path4 file1

but this of course fails in the pattern matching:

./myprog tet . .

myprogt: user error (Pattern match failure in do expression at myprog.hs:11:9-22)

Now, how do I make this program more flexible, so that I can take more than two arguments?

Sorry for asking this, actually, but my Haskell knowledge is limited but increasing for every new thing I have to do in my first project.

Upvotes: 0

Views: 126

Answers (1)

Bakuriu
Bakuriu

Reputation: 101999

Well, you can use a different pattern like:

(dbFile:inputs) <- getArgs

where dbFile will match the first argument passed while inputs will match any number of file names (even 0. If you want at least one path name use inputs@(_:_) instead of the simple inputs).

Then you can use mapM to call findFiles for each path in inputs:

files <- mapM findFiles input
mapM_ putStrLn $ concat files

Instead of mapM you could modify findFiles to accept a [FilePath] argument instead of a simple FilePath.


Note that to parse command arguments you could consider using some module like getopt. You should also read this page about argument handling.

Upvotes: 5

Related Questions