在 haskell 中捕获/劫持标准输出
如何定义“catchOutput”以便运行主输出仅“bar”?
也就是说,如何分别访问 io 操作的输出流(stdout)和实际输出?
catchOutput :: IO a -> IO (a,String)
catchOutput = undefined
doSomethingWithOutput :: IO a -> IO ()
doSomethingWithOutput io = do
(_ioOutp, stdOutp) <- catchOutput io
if stdOutp == "foo"
then putStrLn "bar"
else putStrLn "fail!"
main = doSomethingWithOutput (putStr "foo")
到目前为止,我发现的最好的假设“解决方案”包括转移标准输出, 受此启发,到文件流,然后从该文件中读取(除了超级难看之外,我还无法在从文件写入后直接读取。是否有可能创建一个不必存储在文件中的“自定义缓冲流”?)。尽管这感觉“有点”像是一条岔路。
另一个角度似乎使用“hGetContents stdout”,如果这应该做我认为应该做的事情。但我没有获得从标准输出读取的权限。尽管谷歌搜索似乎表明它已经已使用。
How can I define 'catchOutput' so that running main outputs only 'bar'?
That is, how can I access both the output stream (stdout) and the actual output of an io action separately?
catchOutput :: IO a -> IO (a,String)
catchOutput = undefined
doSomethingWithOutput :: IO a -> IO ()
doSomethingWithOutput io = do
(_ioOutp, stdOutp) <- catchOutput io
if stdOutp == "foo"
then putStrLn "bar"
else putStrLn "fail!"
main = doSomethingWithOutput (putStr "foo")
The best hypothetical "solution" I've found so far includes diverting stdout, inspired by this, to a file stream and then reading from that file (Besides being super-ugly I haven't been able to read directly after writing from a file. Is it possible to create a "custom buffer stream" that doesn't have to store in a file?). Although that feels 'a bit' like a side track.
Another angle seems to use 'hGetContents stdout' if that is supposed to do what I think it should. But I'm not given permission to read from stdout. Although googling it seems to show that it has been used.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我使用以下函数对打印到标准输出的函数进行单元测试。
我不确定内存文件方法,但对于使用临时文件的少量输出来说它可以正常工作。
I used the following function for an unit test of a function that prints to stdout.
I am not sure about the in-memory file approach, but it works okay for a small amount of output with a temporary file.
Hackage 上有一些软件包承诺可以做到这一点:io-capture 和默默地。似乎默默地被维护并且也可以在 Windows 上工作(io-capture 仅在 Unix 上工作)。静默地,您可以使用 capture :
请注意,它的工作原理是将输出重定向到临时文件,然后读取它......但只要它有效!
There are some packages on Hackage that promise to do that : io-capture and silently. silently seems to be maintained and works on Windows too (io-capture only works on Unix). With silently, you use capture :
Note that it works by redirecting output to a temporary file and then read it... But as long as it works !
为什么不直接使用 writer monad 呢?例如,
或者,您可以修改内部操作以采用
Handle
进行写入,而不是stdout
。然后,您可以使用类似 knob创建一个内存中的文件句柄,您可以将其传递给内部操作,然后检查其内容。Why not just use a writer monad instead? For example,
Alternatively, you could modify your inner action to take a
Handle
to write to instead ofstdout
. You can then use something like knob to make an in-memory file handle which you can pass to the inner action, and check its contents afterward.正如 @hammar 指出的,您可以使用旋钮创建内存中文件,但您也可以使用 hDuplicate 和 hDuplicateTo 更改 stdout > 到内存文件,然后再返回。类似于以下完全未经测试的代码:
As @hammar pointed out, you can use a knob to create an in-memory file, but you can also use
hDuplicate
andhDuplicateTo
to changestdout
to the memory file, and back again. Something like the following completely untested code: