Windows 中的 Haskell 中的 UTF-8 input/output

UTF-8 input/output in from Haskell in Windows

下面的简单代码在带有 UTF-8 字符的 Windows 终端中无法正常工作,无论是来自 Prelude 的 getLine/putStrLn 还是来自 Data.Text.IO:

main = forever $ getLine >>= putStrLn

它在输入过程中回显 utf-8 字符,然后打印“?”代替 utf-8 字符;使用 chcp 65001 切换编码使它们成为空格。

我已经下载了新终端并按照 this page 的建议启用了 utf-8 支持,但没有任何效果。

This explanation 似乎相关,但那里提出的解决方案不起作用(代码也是如此)。

显然 python 有一个 similar issue

是否有任何 library/workaround 可以与 GHC 8.x 一起使用?

请帮忙!

编辑:经过更多调查,问题也出在输入过程中——如果我用 mapM_ (print . ord) s 打印字符代码而不是 putStrLn,它们要么是 63 而不改变编码,要么是 0 在 chcp 65001 之后.

hSetEncoding stdin utf8没有帮助

我找到了执行此操作的库:https://hackage.haskell.org/package/terminal

不包含getLine(只有按键事件),但是实现起来很简单:

import Control.Monad.IO.Class (liftIO)
import System.Exit (exitSuccess)
import System.Terminal as C

getTermLine :: MonadTerminal m => m String
getTermLine = getChars ""
  where
    getChars s = awaitEvent >>= processKey s
    processKey s = \case
      Right (KeyEvent key ms) -> case key of
        CharKey c
          | ms == mempty || ms == shiftKey -> do
            C.putChar c
            flush -- works without flush in Windows, but not in Mac
            getChars (c : s)
          | otherwise -> getChars s
        EnterKey -> do
          putLn
          flush
          pure $ reverse s
        BackspaceKey -> do
          moveCursorBackward 1
          eraseChars 1
          flush
          getChars $ if null s then s else tail s
        _ -> getChars s
      Left Interrupt -> liftIO exitSuccess
      _ -> getChars s