Portably opening a handle to stdin many times in a single session

对着背影说爱祢 提交于 2019-12-24 00:58:58

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!