我的 Haskell 程序太懒了

My Haskell program is too lazy

我的函数如下:

type App a = ExceptT AppError (ResourceT IO)

onEvent :: SDL.EventPayload -> App ()
onEvent event = do
  liftIO $ putStrLn "EVE!"
  case event of
    SDL.MouseMotionEvent dat -> do
      liftIO $ putStrLn "HELLO"
    SDL.KeyboardEvent kbe  -> liftIO $ putStrLn "WORLD"
    _ -> return ()

这是我的应用程序中使用的回调。

这个函数似乎没有触发,因为 putStrLn 的 none 打印到控制台。

但是这个函数 - 稍作修改就可以将所有内容打印到控制台:

onEvent :: SDL.EventPayload -> App ()
onEvent event = do
  liftIO $ putStrLn "EVE!"
  case event of
    SDL.MouseMotionEvent dat -> do
      liftIO $ print dat
    SDL.KeyboardEvent kbe  -> liftIO $ print kbe
    _ -> return ()

为什么 SDL.EventPayload 的完整计算会导致周围的 putStrLn 起作用?

如何使我的函数回调更加可靠?

Thomas pointed out in the comments, this looks like a buffering problem. The System.IO package describes standard buffering behavior

关于如何解决此类问题,您有多种选择。您可以在程序中手动设置缓冲模式:

hSetBuffering stdout NoBuffering

在函数的开头。这将关闭所有缓冲(您也可以选择 LineBuffering)并立即打印到标准输出。

您还可以在每次打印后刷新缓冲区:

SDL.MouseMotionEvent dat -> do
  liftIO $ putStrLn "HELLO"
  hFlush stdout

或者您可以尝试直接打印到具有不同默认缓冲规则的 stderr 句柄:

SDL.MouseMotionEvent dat -> do
  liftIO $ hPutStrLn stderr "HELLO"