继续读取用户键盘输入(如果可用),同时回显最新可用的

Keep reading user keyboard input if available, while echoing back the latest available

以下代码一直在等待用户输入,并在获取时将其回显到屏幕。然后它返回等待输入模式。当它处于这种状态时,它会不断地在屏幕上写一条消息。

import Control.Concurrent
import Data.Maybe
import System.IO

main = do
  hSetBuffering stdin NoBuffering
  future_input <- newEmptyMVar
  forkIO $ (>>) <$> putMVar future_input
                <*> (putStrLn . ("pressed key: " ++) . return)
                =<< getChar
  wait future_input
    where wait future_input = do
          input <- tryTakeMVar future_input
          if isJust input
            then main
            else putStrLn "keep waiting" >> threadDelay 1000000 >> wait future_input

我想获得的是消息 keep waiting 伴随着 可用的 用户输入。

到目前为止我唯一的想法是我应该

  1. future_input
  2. 一起声明另一个MVarlatest_input
  3. 让分叉线程与future_input
  4. 同时填写
  5. if isJust inputelse 中,我应该从 latest_input tryTakeMVar 并且,如果其中有内容(即,根据第 2 点,总是这样,除了第一次),我可以在输出中使用它。

然而,在我这个冒昧的想法中,我认为我也应该让 wait 拿走两个 MVar,因为我在等待时不必失去对他们中任何一个的追踪。同样,即使在 if isJust inputthen 分支中,我也可能会传递 latest_input,这意味着我必须使用 main 以外的函数,它会被 main.

现在,我已经到了这里:

import Control.Concurrent
import Data.Maybe
import System.IO

main = do
  hSetBuffering stdin NoBuffering
  future_input <- newEmptyMVar
  latest_input <- newEmptyMVar
  forkIO $ ((>>) .) . (>>)
                <$> putMVar future_input
                <*> putMVar latest_input
                <*> (putStrLn . ("pressed key: " ++) . return)
                =<< getChar
  wait future_input
    where wait future_input = do
          input <- tryTakeMVar future_input
          if isJust input
            then main
            else putStrLn "keep moving" >> threadDelay 1000000 >> wait future_input

呃,我想我明白了 :D(我已经把它放在 Code Review 中了)。

import Control.Concurrent
import Data.Maybe
import System.IO

main = do
  hSetBuffering stdin NoBuffering
  future_input <- newEmptyMVar
  latest_input <- newEmptyMVar
  putMVar latest_input 'A' -- assuming a previous input the first time
  work future_input latest_input

work :: MVar Char -> MVar Char -> IO ()
work future_input latest_input = do
  forkIO $ ((>>) .) . (>>)
                <$> putMVar future_input
                <*> tryPutMVar latest_input
                <*> (putStrLn . ("pressed key: " ++) . return)
                =<< getChar
  wait future_input latest_input
    where wait future_input latest_input = do
          input <- tryTakeMVar future_input
          old_input <- takeMVar latest_input
          if isJust input
            then do
              putMVar latest_input (fromJust input)
              work future_input latest_input
            else do
              putMVar latest_input old_input
              putStrLn ("latest input was " ++ (return old_input))
                >> threadDelay 1000000
                >> wait future_input latest_input