我有一个懒惰IO的问题,但我不知道如何解决。
我这里有三个小的测试程序,但V2是我真正想要的
在某个地方,似乎要么getContents提前停止,要么gnuplot提前完成了编写。
问题的关键是"我如何从stdin中获取内容,并在这里使用gnuplot进行绘图",但我也想知道如何调试底层问题。
版本1,没有处理gnuplot。使用paste <(seq 10000) <(seq 10000) | runhaskell /tmp/hasktest2.hs
运行,按预期打印出(10000.0,10000.0)
。显然,所有stdin都已加载。
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:试图绘制来自stdin的内容。这是以与V1相同的方式运行的——gnuplot生成的临时文件被截断,所以我没有得到绘图。然而,如果我使用1000而不是10k运行,它确实有效——在编写gnuplot csv文件时,它会在某个时候被截断,所以我有一行看起来像1767.0, 1767
,但没有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:只是为了测试gnuplot实际上可以处理10k个点,并将它们写入一个文件——正如预期的那样,这会生成一个图。
import Graphics.Gnuplot.Simple
main = plotPathStyle [] (PlotStyle Points (DefaultStyle (1))) (zip [1..10000] [1..10000] :: [(Double, Double)])
这在很大程度上取决于比赛条件,你最终会得到什么,以及你是否得到了一个图。
函数plotPathStyle
派生一个新的Haskell线程,在该线程中调用gnuplot
。这个线程使用您传递的列表,所以如果列表是通过懒惰IO获得的,那么只有这个线程会真正读取文件。函数plotPathStyle
或多或少会立即返回,在主线程结束时,程序将关闭。
因此,根据调度的方式,您可能会看到被截断的输出或根本没有gnuplot窗口。(如果我真的编译了程序,而不是通过runhaskell
调用,我通常不会得到任何绘图。)即使强制列表也不会让你摆脱这种情况。如果您想要非交互式使用(即不在GHCi中使用),gnuplot
软件包似乎建议使用Graphics.Gnuplot.Advanced
中的接口,这会给您更多的控制权,例如允许您明确等待绘图完成。