Christopher King
Christopher King

Reputation: 10941

`stdin` and `stdout` handle

I am testing a program. Specifically, I am testing a function in isolation. It requires a handle that can be both read and wrote. The problem is, stdin or stdout alone can't do the job. I don't want to rewrite my code just because of such a test, nor do I want to have to open up a socket just for a test either. Also, the program isn't usable yet (have the functions are undefined) so I can't just test it by running it.

What is a handle that gets it input from stdin and output from stdout in haskell.

Upvotes: 7

Views: 2039

Answers (1)

Gabriella Gonzalez
Gabriella Gonzalez

Reputation: 35089

One simple way to do this is to use a Pipe to abstract out reads and writes to handles. One type you can use is:

example :: Monad m => Pipe String String m ()

For example, let's say that your original code looked something like this:

original :: IO ()
original = do
    str1 <- getLine
    str2 <- getLine
    putStrLn (str1 ++ str2)

The new pipes version would look like this:

import Pipes

example :: Monad m => Pipe String String m ()
example = do
    str1 <- await
    str2 <- await
    yield (str1 ++ str2)

Then, you can test it purely like this:

>>> import qualified Pipes.Prelude as Pipes
>>> Pipes.toList (each ["Hello, ", "world!"] >-> example)
["Hello, world!"]

... or you can test it with real input and output:

>>> runEffect $ Pipes.stdinLn >-> example >-> Pipes.stdoutLn
Hello, <Enter>
world!<Enter>
Hello, world!

This lets you keep your main logic pure, and then choose whether or not to run it purely or impurely.

Upvotes: 18

Related Questions