Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shorten code which handles IO

Tags:

haskell

scala

I have written a small piece of code which handles the input of a console:

main :: IO ()
main = do
  input <- readLine "> "
  loop input

loop :: String -> IO ()
loop input = do
  case input of
    [] -> do
      new <- readLine "> "
      loop new
    "quit" ->
      return ()
    _ -> do
      handleCommand input
      new <- readLine "> "
      loop new

handleCommand :: String -> IO ()
handleCommand command = do
  case command of
    "a" -> putStrLn "it was a"
    "b" -> putStrLn "it was b"
    _ -> putStrLn "command not found"

readLine :: String -> IO String
readLine prompt = do
  putStr prompt
  line <- getLine
  return line

The code works fine, but it looks ugly and is redundant. In Scala I succeeded to write it shorter:

object Test extends App {
  val reader = Iterator.continually(readLine("> "))
  reader takeWhile ("quit" !=) filter (_.nonEmpty) foreach handleCommand

  def handleCommand(command: String) = command match {
    case "a" => println("it was a")
    case "b" => println("it was b")
    case _ => println("command not found")
  }
}

I tried to use higher-order functions with the IO Monad in Haskell but I failed. Can someone give me an example how to shorten the Haskell code?

Another problem is that the order of output is different. In Scala it is correct:

$ scala Test
> hello
command not found
> a
it was a
> b
it was b
> quit

Whereas in Haskell it is not:

$ ./test
hello
> command not found
a
> it was a
b
> it was b
quit
> %

How to solve this?

like image 623
kiritsuku Avatar asked Feb 28 '12 00:02

kiritsuku


1 Answers

import System.IO

main = putStr "> " >> hFlush stdout >> getLine >>= \input ->
    case input of
        "quit" -> return ()
        "a"    -> putStrLn "it was a" >> main
        "b"    -> putStrLn "it was b" >> main
        _      -> putStrLn "command not found" >> main

Shorter and clearer than Scala imo.

like image 55
qubital Avatar answered Oct 04 '22 21:10

qubital