Jos*_*ica 5 c stdin haskell eof io-monad
我有以下C程序:
#include <stdio.h>
#include <unistd.h>
void readAndEchoAll(void) {
for(;;) {
char buf[100];
ssize_t size = read(STDIN_FILENO, buf, sizeof(buf));
if(size <= 0) {
return;
}
fwrite(buf, 1, size, stdout);
}
}
int main(void) {
puts("Reading and echoing STDIN until first EOF...");
readAndEchoAll();
puts("Got first EOF. Now reading and echoing STDIN until second EOF...");
readAndEchoAll();
puts("Got second EOF.");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我运行它时,它会按照我想要的方式工作。这是它的作用:
Reading and echoing STDIN until first EOF...
asdf
^Dasdf
Got first EOF. Now reading and echoing STDIN until second EOF...
fdsa
^Dfdsa
Got second EOF.
Run Code Online (Sandbox Code Playgroud)
我正在尝试创建一个等效的Haskell程序。这是我的尝试:
readAndEchoAll :: IO ()
readAndEchoAll = do
buf <- getContents
putStr buf
main :: IO ()
main = do
putStrLn "Reading and echoing STDIN until first EOF..."
readAndEchoAll
putStrLn "Got first EOF. Now reading and echoing STDIN until second EOF..."
-- ???
readAndEchoAll
putStrLn "Got second EOF."
Run Code Online (Sandbox Code Playgroud)
这行不通。这是它的作用:
Reading and echoing STDIN until first EOF...
asdf
^Dasdf
Got first EOF. Now reading and echoing STDIN until second EOF...
readtwice.hs: <stdin>: hGetContents: illegal operation (handle is closed)
Run Code Online (Sandbox Code Playgroud)
如何使这项工作像C程序一样?我假设我需要把clearerr(stdin);我所拥有的位置等同起来-- ???,但是我不确定那是什么。
Update: Turns out clearerr is a bit of a red herring, as it's exclusive to the standard C API. When using the POSIX API, you can just read again without needing to do anything equivalent to it. So rather than make Haskell do anything extra, I need to make it not do something: not prevent further reads once it sees EOF.
您不能使用getContents,因为hGetContents(半)关闭了它传递的句柄并getContents调用hGetContents。但是,在EOF之后使用标准库中的大多数其他功能再次从句柄读取没有问题。这是不使用读取所有字符的简单但效率低下的示例getContents:
import Control.Exception
import System.IO.Error
readAll = go [] where
handler cs err = if isEOFError err
then return (reverse cs)
else throwIO err
go cs = catch (do
c <- getChar
go (c:cs))
(handler cs)
main = do
all <- readAll
putStrLn $ "got: " ++ all
putStrLn "go again, mate"
all <- readAll
putStrLn $ "got: " ++ all
Run Code Online (Sandbox Code Playgroud)
如果要提高效率,可以使用各种功能来一次读取行或在标准库中读取其他大块数据,而不是一次读取一个字符。