Simple newbie-friendly CLI parser?

Want to write some simple command line tool with Haskell – and want to use the opportunity to learn a CLI parser library.

However I’m a beginner and haven’t really looked topics like “applicative” or “monads”. (I’m using IO just as I go.)

What CLI library is recommend for somebody who starts out with Haskell?

I had a look at Turtle, but it comes with so many other baggage I won’t use…

LHBG has a chapter about optparse-applicative Fancy options parsing - Learn Haskell by building a blog generator

3 Likes

It has the word “applicative” in the name, but the documentation and examples on this page for the optparse-applicative package are quite extensive and I’d recommend giving it a go: optparse-applicative: Utilities and combinators for parsing command line options

In a typical Haskell way, setting up a CLI parser can be extremely smooth if you know what to do (e.g. you can automatically create on like here: Generic Programming - The Haskell Guide) but a bit confusing if you don’t.

4 Likes

If you are just working with IO avoiding applicatives then I’d say you start with

-- This functions takes the list of arguments and returns something of your interest
-- the list of arguments look like ["--verbose","2","--color", "always", "-f" etc...]
yourOwnSimpleParser :: [String] -> SomeUserDefinedType
yourOwnSimpleParser = undefined

main = do
  list_of_arguments <- getArgs
  yourOwnSimpleParser list_of_arguments
  ...

Once you convice yourself writing your own parser is a bad idea, go with optparse-applicative. Despite of its applicative interface, you’ll see it is actaully very easy to use.

Then you should checkout Iris too, which is built on top of optparse-applicative and is a more complete CLI framework, with good documentation. Probably you need a little bit of experience to use it headachelessly (is this even a word?)

3 Likes

@gilmi @reuben @Lsmor Thanks for all your encouragement - i might try optparse-applicative then.

1 Like

You can also use optparse-generic, a wrapper on optparse-applicative. You can take a look at the haddock in the main module, it explains basic concepts.

3 Likes

Using optparse-applicative is certainly more friendly than trying to invent arg parser from scratch.

And if you don’t like a tree of <$> <*> etc, you can use do notation to collect your option record fields:

data Options = Options
  { output :: FilePath
  } deriving (Show)

optionsP :: Parser Options
optionsP = do
  output <-
    optional . strOption $ -- parsing aspects
      mconcat -- or use (a <> b <> ...)
        [ long "output"
        , short 'o'
        , metavar "FILENAME"
        ]  -- option aspects
  -- add more stuff likewise
  pure Options{..} -- collect all the parsed fields
3 Likes

Note that @wiz’s suggestion needs {-# LANGUAGE ApplicativeDo #-} enabled. Other than that, this is my preferred approach - optparse-applicative + ApplicativeDo.

I have a very thin layer over optparse-applicative called simple-cmd-args which has served me pretty well for my cli tools.

Obligatory vote for cmdargs, which is full-featured, one package, with a choice of simple or powerful API.

2 Likes

Wow, I hadn’t seen that package yet. It looks like the author has spent a lot of effort subverting Haskell. Although I don’t think I’d say more is gained than lost.

1 Like

Interesting. Would you mind explain why/how cmdargs subverts Haskell? I guess you mean it is not very “haskellonic”. I guess optparse-applicative is more haskellonic? Why?

Please excuse my dumb questions, but I’m just starting out with Haskell.

You can compare examples for optparse-applicative that just rides Applicative and Monoid instances with example for cmdargs with its use of type reflection and partial values.

With one you can open the library source and get a good understanding of how it was made even you’re fresh off the tutorial, but not so with the other.

1 Like