2016-11-21 72 views
1

我想在没有传输光标到下一行的Haskell中使用readline。如何在Haskell中进行readline而不转移到下一行?

例如,我写了下面的代码:

readEvalPrintLoop :: IO() 
readEvalPrintLoop = do 
    line <- getLine 
    case line of 
      "bye" -> return() 
      line -> do putStrLn $ interpret line 
         readEvalPrintLoop 

启动程序后:

> 1 2 + . <enter> 
3 

但我想找得到遵循最简单的方法

> 1 2 + . <enter> 3 
+0

@Bakuriu是的,它应该是你提到的输入缓冲。请注意,此缓冲区不存在于Haskell应用程序中,而是存在于终端中(OS内核或终端仿真程序中)。默认情况下,终端响应每个键并像往常一样移动光标,而不与应用程序进行任何交互。应用程序可以要求终端改变这种默认行为,实际上ncurses是一种常见的方式。 – chi

+0

@Bakuriu缓冲只与切线相关:这里真正的问题是回声。在我的回答中,我还*关闭缓冲区,但不阻止换行符的出现;相反,它允许所有其他内容一次出现,而不是缓冲区大小的块! –

+0

@Andrei如果你和我一样,这个问题可能导致你想知道到底发生了什么以及哪些行为是可配置的。你可以在[The TTY demystified](http://www.linusakesson.net/programming/tty/)上阅读更多关于它的内容,但我警告你:如果你只想完成任务,这将会是方式更多的信息比你想要的! –

回答

1

当你按下enter键 - 当你按任何其他ke y - 它被打印到屏幕上。您可以关闭此行为与hSetEcho

main = do 
    hSetEcho stdin False 
    readEvalPrintLoop 

但是,如果你这样做,你会发现这个有一些附带损害:在输入不再回荡,但也不是其他任何你的类型,所以它看起来就像你输入的所有东西都是隐形的!您可以通过手动实施修改后的回应策略来解决此问题。您需要做两件事:将输入流设置为无缓冲模式,使用hSetBuffering(以便您立即接收输入,而不是在行尾)并打印您收到的每个非输入字符。所以:

myGetLine :: IO String 
myGetLine = do 
    c <- getChar 
    case c of 
     '\n' -> return "" -- don't echo newlines 
     _ -> do 
      putChar c -- do echo everything else 
      fmap (c:) myGetLine 

readEvalPrintLoop :: IO() 
readEvalPrintLoop = do 
    line <- myGetLine -- getLine changed to myGetLine 
    case line of 
      "bye" -> return() 
      line -> do putStrLn $ interpret line 
         readEvalPrintLoop 

main = do 
    hSetEcho stdin False 
    hSetBuffering stdin NoBuffering 
    readEvalPrintLoop 
+0

N.B.根据你想要的行为,你可能想在'myGetLine'中检查EOF。 –

相关问题