Search code examples
haskellfunctional-programminglambda-calculus

Haskell: a for loop for a REPL


I am trying to write a something like a repl in Haskell and I want to replicate this code in C:

for (int c = getc(stdin); c != 'e'; c = getc(stdin)) {
        printf("I got %c!\n", c);
}

I could use recursion but I am afraid of exeeding the limit.


Solution

  • You should use recursion. Haskell is designed to handle recursion without limits, and recursion can and should be used even for effectively infinite loops (e.g., event processing loops or REPL loops).

    So, you could more or less write your program as follows:

    main = do
      txt <- getLine
      if txt /= "exit" then do
        putStrLn $ "I got " ++ txt ++ "!"
        main
      else do
        return ()
    

    giving:

    $ ./repl
    foo
    I got foo!
    bar
    I got bar!
    exit
    $ 
    

    I've written it to grab a whole line of input instead of single character, since there are typically issues with buffered input when trying to grab input character by character. This infinite recursion works fine and will not exceed any limit no matter how many billions of lines it processes before exiting.

    In most real-world programs, you don't want the whole main program to loop, so you typically write something like the following. Here, I've used when which is a nicer looking way of writing the pattern if xxx then yyy else return ().

    import Control.Monad  -- for definition of "when"
    
    main = do
      -- initialization
      putStrLn $ "Welcome to my REPL!"
      -- start the main loop
      loop
      -- clean up
      putStrLn $ "Thanks so much for using my REPL!"
    
    -- definition of main loop
    loop = do
      txt <- getLine
      when (txt /= "exit") $ do
        putStrLn $ "I got " ++ txt ++ "!"
        loop