【问题标题】:Haskell cross-platform getChar with NoBuffering带有 NoBuffering 的 Haskell 跨平台 getChar
【发布时间】:2021-06-06 17:34:39
【问题描述】:

Haskell 有 a bug in Windows,看起来像 fixed with WinIO in GHC9:getChar 忽略 NoBuffering 模式 - 在按下 Enter 之前它不会计算。

某人suggested 通过外来电话解决方法:

{-# LANGUAGE ForeignFunctionInterface #-}
import Data.Char
import Foreign.C.Types
getHiddenChar = fmap (chr.fromEnum) c_getch
foreign import ccall unsafe "conio.h getch"
  c_getch :: IO CInt

它有点工作,但问题是它似乎阻止输出到控制台,直到按下某个键,我同时读取按键并从不同线程写入控制台。

您能否帮助找到一种方法(例如,编写一个外部函数调用 - 不幸的是,我对此了解不多)在 GHC 中从控制台读取字符/键,无需缓冲和回显,也不会阻塞到控制台的输出8.8.x(或至少 8.10.x),在 Windows 上?

谢谢!

(理想情况下我需要一种跨平台的方式,但是我可以通过条件编译来实现,所以如果它只适用于Windows就可以了。上面的外部调用已经不是跨平台的了)。

【问题讨论】:

    标签: windows haskell io ghc


    【解决方案1】:

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

    它在等待按键时不会阻塞,您仍然可以从另一个线程打印。

    还解决了Windows终端utf8 problem

    【讨论】:

      【解决方案2】:

      该特定 FFI 调用的基本问题是 unsafe。这使得getch 发生在调用(系统)线程中。通常,可能需要一些时间的外来电话应标记为safe。即使这样也有点问题,因为异常(例如,来自用户按 Ctrl-C 的)被屏蔽了。

      此类 FFI 调用的真正解决方案是将其标记为interruptible,然后正确处理中断。您可以通过检查调用是否成功(基于其返回值)来执行此操作。如果不是,那么您将检查errno 是否有EINTR 并在这种情况下再试一次,就像任何此类外国电话一样。但是对于interruptible,如果你得到EINTR,你应该在重试之前使用allowInterrupt传递异步异常。

      警告:上述方法仅适用于(大部分)进行可中断系统调用的外部调用,并且以失败状态终止并在中断时设置 EINTR。例如,执行昂贵的数学计算的外部函数通常根本不可中断。

      注意:在同一个文件描述符上混合基于 Handle 的 I/O 和原始 FFI I/O 听起来很麻烦。

      【讨论】:

      • > 在同一个文件描述符上混合基于句柄的 I/O 和原始 FFI I/O 听起来像是麻烦的秘诀。即使只有一个线程写,只通过句柄,另一个线程读,只通过FFI?
      • @esp,我不能肯定地说。可能没问题,但我不是这方面的专家。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-20
      • 2010-11-04
      • 2014-11-20
      相关资源
      最近更新 更多