[Haskell] ANNOUNCE: HCL v1.0 -High-level library for building command line interfaces

Justin Bailey jgbailey at gmail.com
Mon Jul 9 18:28:57 EDT 2007

I'm please to announce HCL 1.0 - a library for building command line
interfaces. The library exports a mix of low and high-level functions
for building programs which gather simple values, ask yes/no
questions, or present hierarchical menus. The library is not intended
to do complex, full-screen UIs ala ncurses - it is intended for
line-oriented interfaces.

Included with the library is a hangman game, so if nothing else you
can enjoy that.

Where do I get it?

Download from Hackage at:


How do I use it it?

It's Cabal-ized so, after downloading and unpacking:

  runghc Setup.hs configure
  runghc Setup.hs build
  runghc Setup.hs install

Note I had some inconsistent results building with HEAD cabal, but the
version distributed with GHC works great (

To play hangman, execute 'hangman'. Once installed, you can look at it
in GHCi by loading the "HCL" module.

Tell me more!

This library lets you do a lot of cool things. For example, here's a
simple guess a number game:

 guess_num_fun =
         target <- reqIO $ getStdRandom (randomR (1::Integer,100))
         let guessed val =
               case compare target val of
                 GT -> do { reqIO $ putStrLn "Too low!"; return False }
                 LT -> do { reqIO $ putStrLn "Too high!"; return False }
                 EQ -> do { reqIO $ putStrLn "You win!"; return True }
         reqUntil guessed (prompt "Enter a number between 1 and 100: "

"reqUntil" takes a predicate and asks for a response until the
predicate is true. In the case above, the user is asked to enter an
integer. Once they guess the number, the program ends.

The library makes it easy to gather structured values. For example,
imagine this data structure:

  data Taxpayer = Taxpayer { name :: String, age :: Int, ssn :: String }
     deriving (Read, Show)

One way to use HCL to get Taxpayer values from the user is to take
advantage of its Read instance:

 reqTaxpayer :: Request Taxpayer
 reqTaxpayer = prompt "Please enter tax payer information: " (reqRead reqResp)

But that is ugly because the user has to type a "Read"-able string:

 > getTaxpayer reqTaxpayer
 Please enter tax payer information: Taxpayer {name="John", age = 30, ssn = "" }

However, we can build a form of sorts and make life much easier for the user:

 reqTaxpayerEasy :: Request Taxpayer
 reqTaxpayerEasy =
     name <- prompt "Please enter the tax payer's name: " reqResp
     age <- prompt "Please enter their age: " reqInt
     ssn <- prompt "What is their SSN/ASN: " reqResp
     return (Taxpayer name age ssn)

Which looks like this:

 > getTaxpayer reqTaxpayerEasy
 Please enter the tax payer's name: Bob
 Please enter their age: 50
 Please enter their SSN/ASN: 111-11-1111

The library also makes simple hierarchical menus easy to build. The
below defines the menu structure for a hypothetical PIM:

   reqMenu $
   reqSubMenu topMenu "Manage contacts" manageContactsMenu $
   reqSubMenu topMenu "Manage calendar"
     (reqMenuItem "Add an event" ... $
       reqMenuExit "Return to previous menu"
       reqMenuEnd) $
   -- End the menu definition

 -- Defines a partial menu
 manageContactsMenu =
   reqMenuItem "Add a contact" ... $
   reqMenuExit "Return to previous menu"

These and more examples are distributed with the library in the
examples directory.

Anything else?

Feedback, praise and criticism are welcome. Feedback regarding
'idiomatic' usage is especially desired. This is a first for me so any
responses are appreciated.

The library was developed on Windows using GHC - please let me know of
any odd *nix and Hugs bugs.

This library was inspired in part by the Ruby HighLine library
(http://highline.rubyforge.org/).  Many thanks Mark Jones for his
input on HCL's design and implementation.

More information about the Haskell mailing list