3

我遇到了惰性 IO 的问题,但我不知道如何解决它。
我在这里有三个小型测试程序,但 V2 是我真正想要的东西。
在某个地方,似乎 getContents 提前停止了,或者 gnuplot 提前完成了编写。

问题的关键是'我如何从标准输入中获取东西,并在此处使用 gnuplot 进行绘制',但我也想知道如何调试潜在问题。

版本 1,不处理 gnuplot。运行,按预期paste <(seq 10000) <(seq 10000) | runhaskell /tmp/hasktest2.hs打印。(10000.0,10000.0)显然所有标准输入都已加载。

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:尝试绘制来自标准输入的任何内容。这与 V1 的运行方式相同 - gnuplot 生成的临时文件被截断,所以我没有得到绘图。但是,如果我使用 1000 而不是 10k 运行,它确实可以工作 - 在编写 gnuplot csv 文件时它会在某些时候被截断,所以我有一条看起来像1767.0, 1767no的行\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)])
4

1 回答 1

3

这在很大程度上取决于比赛条件,你最终会得到什么,以及你是否得到了一个情节。

该函数plotPathStyle派生了一个新的 Haskell 线程,在该线程中gnuplot被调用。这个线程使用你传递的列表,所以如果列表是通过惰性 IO 获得的,那么只有这个线程会真正读取文件。该函数plotPathStyle或多或少立即返回,并且在主线程结束时,程序将关闭。

因此,根据调度的发生方式,您可能会看到截断的输出或根本没有 gnuplot 窗口。(如果我真的编译程序而不是调用 via runhaskell,我通常不会得到任何情节。)即使强制列表也不会让你摆脱这种情况。如果您想要非交互式使用(即,不在 GHCi 中),似乎该gnuplot软件包建议使用 中的接口Graphics.Gnuplot.Advanced,这为您提供了更多控制权,例如允许您明确等待绘图完成。

于 2015-03-04T12:07:34.440 回答