问题
Code:
main = do
putStrLn "4917 Microprocessor\nEnter the Machine Code to be run: "
inp <- getContents
putStrLn "The output of the Program is:"
fState <- ((runStateT _4917) . construct . parse) inp
args <- getArgs
if elem "-v" args then putStrLn ("\nFinal state was: " ++ (show . snd) fState) else return ()
putStrLn "\n================================ RESTART ================================"
main
where parse xs = array (0,15) $
zip [0..15] $
take 16 $
map ((makeArbInt 4) . read) (words (filter ((/=)'.') xs)) ++ repeat (makeArbInt 4 0)
construct xs = Program xs z z z z 0 False
z = (makeArbInt 4 0)
There's more but this is the relevant part. Basically line 3 needs to be evaluated multiple times but getContents is closing the stdin handle:
4917: <stdin>: hGetContents: illegal operation (handle is closed)
Is there a way to reopen the handle? Or some way of preventing getContents from doing that? (Maybe I'm sending the wrong signal. I'm sending over a Ctrl-D EOF on Linux. Maybe I should use EOT or something instead?)
edit: I've managed to get the desired behaviour but it won't port to windows.
mystdin <- openFile "/dev/tty" ReadMode
inp <- hGetContents mystdin
New question: is there a generic way to portably open a handle to stdin?
回答1:
You cannot prevent getContents
from closing the file, and a closed file stays closed.
It seems to me that you need some other function. Usually, when you read parts of a file, you know when to stop (end of line, certain bytes on the stream). So yes: If you cannot parse the data that you are reading and detect when it is done, you should use some kind of delimiter (possibly EOT, or an empty line, or special text unlikely to occur in the data like __END__
).
回答2:
Have them enter a blank line to end input:
getContents2 = helper "" where
helper str = do
a <- getLine
if "" == a then return str
else helper (str++"\n"++a)
You might also haven them signal the end of the session by entering a single blank line.
回答3:
To open a handle to stdin portably, use hDuplicate function on the existing stdio handle to get a new one:
mystdin <- hDuplicate stdin
inp <- hGetContents mystdin
Make sure never to close the original stdin, so that you can make more duplicates as appropriate. (I'm not sure if this is good Haskell style)
来源:https://stackoverflow.com/questions/17123897/portably-opening-a-handle-to-stdin-many-times-in-a-single-session