Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Idiomatic way to conditionally process IO in Haskell

I'm writing a little shell script in Haskell which can take an optional argument. However, if the argument is not present, I'd like to get a line from stdin in which to ask for a value.

What would be the idiomatic way to do this in Haskell?

#!/usr/bin/env runhaskell

import Control.Applicative ((<$>))
import Data.Char (toLower)
import IO (hFlush, stdout)
import System.Environment (getArgs)

main :: IO ()
main = do args <- getArgs
          -- here should be some sort of branching logic that reads
          -- the prompt unless `length args == 1`
          name <- lowerCase <$> readPrompt "Gimme arg: "
          putStrLn name

lowerCase = map toLower

flushString :: String -> IO ()
flushString s = putStr s >> hFlush stdout

readPrompt :: String -> IO String
readPrompt prompt = flushString prompt >> getLine

Oh, and if there's a way to do it with something from Control.Applicative or Control.Arrow I'd like to know. I've become quite keen on these two modules.

Thanks!

like image 853
Ionuț G. Stan Avatar asked Apr 21 '11 10:04

Ionuț G. Stan


2 Answers

main :: IO ()
main = do args <- getArgs
          name <- lowerCase <$> case args of
            [arg] -> return arg
            _     -> readPrompt "Gimme arg: "
          putStrLn name
like image 79
fuz Avatar answered Sep 28 '22 06:09

fuz


This doesn't fit your specific use case, but the question title made me think immediately of when from Control.Monad. Straight from the docs:

when :: Monad m => Bool -> m () -> m ()

Conditional execution of monadic expressions.

Example:

main = do args <- getArgs
          -- arg <- something like what FUZxxl did..
          when (length args == 1) (putStrLn $ "Using command line arg: " ++ arg)
          -- continue using arg...

You can also use when's cousin unless in similar fashion.

like image 42
Dan Burton Avatar answered Sep 28 '22 06:09

Dan Burton