Kevin Bradner
Kevin Bradner

Reputation: 438

How can two Haskell programs exchange an integer value via stdin and stdout without treating the data as text?

I am interested in learning how to send data efficiently between Haskell programs using standard input and output. Suppose I want to pipe two programs together: "P1" outputs the number 5 to stdout, and "P2" takes an integer from stdin, adds 1, and outputs it to stdout again. Right now, the best way I know to do this involves outputting the data as text from P1, parsing that text back to an integer in P2, and proceeding from there. For example:

P1.hs:

module Main where

main = do
  print 5

P2.hs:

module Main where

main = fmap manipulateData getLine >>= print
  where
    manipulateData = (+ 1) . (read :: String -> Int)

Output:

$ (stack exec p1) | (stack exec p2)
6

I'd like to use standard i/o to send an integer without treating it as text, if possible. I'm assuming this still requires some sort of parsing to work, but I'm hoping it's possible to parse the data as binary and get a faster program.

Does Haskell have any way to make this straightforward? Since I am going from one fundamental Haskell datatype (Int) to the same type again with a pass through standard i/o in the middle, I'm wondering if there is an easy solution that doesn't require writing a custom binary parser (which I don't know how to do). Can anyone provide such a method?

Upvotes: 4

Views: 115

Answers (1)

Kevin Bradner
Kevin Bradner

Reputation: 438

Here is the code that I ended up with:

module Main where

import qualified Data.ByteString.Lazy as BS
import qualified Data.Binary as B

main :: IO ()
main = do
  dat <- BS.getContents
  print $ (B.decode dat :: Int) + 1

The other program uses similar imports and outputs 5 with the following line:

BS.putStr $ B.encode (5 :: Int)

The resulting programs can be piped together, and the resulting program behaves as required.

Upvotes: 2

Related Questions