Ionuț G. Stan
Ionuț G. Stan

Reputation: 179098

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!

Upvotes: 7

Views: 861

Answers (2)

fuz
fuz

Reputation: 92966

main :: IO ()
main = do args <- getArgs
          name <- lowerCase <$> case args of
            [arg] -> return arg
            _     -> readPrompt "Gimme arg: "
          putStrLn name

Upvotes: 9

Dan Burton
Dan Burton

Reputation: 53665

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.

Upvotes: 2

Related Questions