我的Haskell程序太懒了

Dan*_*ill 7 haskell lazy-evaluation

我有一个功能:

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 ()
Run Code Online (Sandbox Code Playgroud)

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

这个函数看似不会触发,因为没有putStrLn的打印到控制台.

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

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 ()
Run Code Online (Sandbox Code Playgroud)

为什么全面评估SDL.EventPayload导致周围putStrLn的工作?

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

jke*_*len 1

正如托马斯在评论中指出的那样,这看起来像是一个缓冲问题。该System.IO包描述了标准缓冲行为。

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

hSetBuffering stdout NoBuffering
Run Code Online (Sandbox Code Playgroud)

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

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

SDL.MouseMotionEvent dat -> do
  liftIO $ putStrLn "HELLO"
  hFlush stdout
Run Code Online (Sandbox Code Playgroud)

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

SDL.MouseMotionEvent dat -> do
  liftIO $ hPutStrLn stderr "HELLO"
Run Code Online (Sandbox Code Playgroud)