Karl Hans Janke Kollaborativ
Heute die Welt, morgen das Sonnensystem!
<< prev next >>

Command line flags for Haskell scripts, Really Cheap & Simple (TM)

How often do you find yourself in the following situation?

Having written a nice little program, you just want to add one little command line option. Typical example: -dprint debugging output. So all you want to say (in code) is something like this:

If we were given the '-d' flag on the command line,
... [print/enable debug output]

But what you actually have to do is usually this:

Seem a bit much? Not that there is anything wrong with the above in principle. These libraries are very useful for writing compilers and faithful reproductions of historic UNIX utilities. But for your everyday script? I think it's annoying.

So, speaking of returns to simplicity. These are for pasting into your next Haskell script:

import System.Environment

-- pesco's really cheap and simple flags and options (tm)
clparts = getArgs >>= return . (\(a,b) -> (a,drop 1 b)) . break (=="--")
getargs = clparts >>= \(a,b)-> return ([h:t| h:t<-a, h/='-' || null t] ++ b)
getflags = clparts >>= \(a,_)-> return (concat [t| '-':t <- a])
getflag x = getflags >>= return . elem x
getenv f v x = catch (getEnv v >>= return . f) (\_ -> return x)

Here, have some type signatures, too:

getargs  :: IO [String]
getflags :: IO [Char]
getflag  :: Char -> IO Bool
getenv   :: (String -> a) -> String -> a -> IO a

Usage of the functions is pretty apparent from the types. Don't look anything up. Please!

From five lines you get:

You buy simplicity at the expense of comprehensiveness. What you don't get:

PS. I did make an elaborate command line parsing library a few years ago. Suitable for building big compilers and stuff! You might still find it in the caches of the intarweb if you're interested. Reading the original abstract, the goal was similar then: Make it really easy to get command line options into programs. Alas, using that library still suffered from problems outlined at the top of this post: Find it, look through the docs, add a big bunch of code to your project, use an elaborate API. I think it was a very good replacement for the standard GetOpt; considerably nicer, with many fancy features. But probably overkill for everyday use in scripts or small programs.