2016-11-21 24 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。 –

相關問題