Running haskell executable using Java ProcessBuilder: why does hGetLine only return after closing outputStream?

I am terminating a FM-SBLEX Saldo program in a Java library.

Saldo is written in Haskell and searches the lexicon for strings given to stdin, for example

echo "ord"|./sblex/bin/saldo dicts/saldo.dict

      

outputs something like the following to stdout

{"ord":{"s_1":{"word":"ord","head":"sanna mina ord","pos":"abm","param":"invar 1:3-3","inhs":[],"id":"sanna_mina_ord..abm.1","p":"abm_i_till_exempel","attr":"3"},...

      

If I run it with

./sblex/bin/saldo dicts/saldo.dict

      

it searches every line I typed in the console until I submit an EOF.

In my Java library, I run it with ProcessBuilder and set up a stream to output stdout and stderr to my stdout program, and another stream writes word and newline and then clears the outputStream

On the console, saldo returns results every time I hit return, but in my wrapper, it only returns results for all of my input once when I close the outputStream (see close () commented out in the following code block)

    ProcessBuilder pb = new ProcessBuilder(binPath, dictPath);

    pb.redirectErrorStream(true);
    saldoProcess = pb.start();

    new Thread(new Reader(saldoProcess.getInputStream())).start();
    new Thread(new Writer(saldoProcess.getOutputStream())).start();

    saldoProcess.waitFor();
    System.out.println("saldo exited.");
    Thread.sleep(2000);

      

Shutting down Writer:

    public void run() {
        try {
            outputStream.write("ord\n".getBytes());
            outputStream.flush();
            //outputStream.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

      

Haskell code that reads input

run' :: Language a => a -> (String -> [Tok]) -> (String -> [[String]]) -> AnaType -> Stats -> IO Stats
run' l tokenizer f a st = 
 do b <- hIsEOF stdin
    if b then return st 
     else do 
       s <- hGetLine stdin
       analyze l a f (tokenizer s) st >>= run' l tokenizer f a

      

If binPath = "cat" and dictPath = "-" then my java program prints the input after every reset. Any idea why this haskell program only deals with input after closing the output stream?

NB: as the answer shows, there was no hGetLine that didn't return (as I assumed), but output that was buffered because the Haskell implementation I use by default to block the buffer if it is not run from the console.

+3


source to share


1 answer


Your Haskell program is probably buffering its output. (Buffered line by line when writing to the terminal, buffered when writing to anything else.)

Try adding

hSetBuffering stdout LineBuffering

      



near the start of the program.

Learn more about buffering in Haskell.

(Edited in response to comment by Daniel Wagner.)

+4


source







All Articles