I'm having an issue with lazy IO, but I don't know how to fix it.
I've got three small test programs here, but with V2 being the thing I actually want.
Somewhere, it seems that either getContents is being halted early, or gnuplot is finishing writing early.
The crux of the question is 'how can I take stuff from stdin, and plot it with gnuplot here', but I'd also like to know how to debug the underlying problem.
Version 1, no dealing with gnuplot. Run with paste <(seq 10000) <(seq 10000) | runhaskell /tmp/hasktest2.hs
, prints out (10000.0,10000.0)
as expected. Clearly all of stdin is loaded.
import Data.List
main = do
contents <- getContents
print . last . map f . lines $ contents
f :: String -> (Double, Double)
f s = (read x, read y)
where
[x,y] = words s
V2: Attempting to plot whatever comes from stdin. This is run the same way as V1 - the temporary file that gnuplot makes gets truncated, so I don't get a plot. However, if I run with with 1000 instead of 10k, it does work - it gets truncated at some point when writing the gnuplot csv file, so I have a line that looks like 1767.0, 1767
with no \n
.
main = do
contents <- getContents
plotPathStyle [] (PlotStyle Points (DefaultStyle (1))) . map f . lines $ contents
f :: String -> (Double, Double)
f s = (read x, read y)
where
[x,y] = words s
V3: Just to test that gnuplot can actually deal with 10k points, and write them to a file - this produces a plot, as expected.
import Graphics.Gnuplot.Simple
main = plotPathStyle [] (PlotStyle Points (DefaultStyle (1))) (zip [1..10000] [1..10000] :: [(Double, Double)])
It's very much depending on a race condition what you'll end up getting, and whether you get a plot at all.
The function plotPathStyle
forks a new Haskell thread in which gnuplot
is called. This thread makes use of the list you pass, so if the list is obtained via lazy IO, only this thread will actually read the file. The function plotPathStyle
returns more or less immediately, and at the end of the main thread, the program will shut down.
So depending on how scheduling occurs, you may see truncated output or no gnuplot window at all. (If I actually compile the program rather than invoke via runhaskell
, I usually get no plot whatsoever.) Even forcing the list won't save you from this condition. If you want non-interactive use (i.e., not from within GHCi), it seems that the gnuplot
package recommends the interface in Graphics.Gnuplot.Advanced
, which gives you more control and e.g. allows you to wait explicitly for the plot to finish.