Haskell 如何安全地中止getChar?

Haskell 如何安全地中止getChar?,haskell,io,Haskell,Io,我想选择性地中止getChar操作。 我需要以下功能: getChar' :: (Char -> IO ()) -> IO (IO ()) 如果是中止IO())->IO(IO()) getChar'callback=do v您要做的是使用异常处理结构,这样无论出现什么异常,MVar都始终处于安全状态。特别是,您可能需要使用MVAR我认为实现这一点的最简单方法是执行您自己的缓冲。这是一个简单的原型。它假定您在程序中只调用一次launchIOThread。它不处理EOF或其他IO异常,

我想选择性地中止
getChar
操作。 我需要以下功能:

getChar' :: (Char -> IO ()) -> IO (IO ())
如果是
中止IO())->IO(IO())
getChar'callback=do

v您要做的是使用异常处理结构,这样无论出现什么异常,MVar都始终处于安全状态。特别是,您可能需要使用MVAR

我认为实现这一点的最简单方法是执行您自己的缓冲。这是一个简单的原型。它假定您在程序中只调用一次
launchIOThread
。它不处理EOF或其他IO异常,但这应该很容易

import Control.Concurrent
import Control.Concurrent.STM
import Data.Maybe
import Control.Monad

type Buffer = TVar (Maybe Char)

launchIOThread :: IO Buffer
launchIOThread = do
  buf <- atomically $ newTVar Nothing
  _ <- forkIO $ ioThread buf
  return buf

ioThread :: Buffer -> IO ()
ioThread buf = loop where
  loop =
    join $ atomically $ do
      contents <- readTVar buf
      if isJust contents -- no-one has taken the character yet
        then retry -- relax
        else return $ do
          c <- getChar
          atomically $ writeTVar buf (Just c)
          loop

getChar' :: Buffer -> (Char -> IO ()) -> IO (IO ())
getChar' buf callback = do
  abortFlag <- atomically $ newTVar False

  _ <- forkIO $ doGetChar abortFlag

  return $ atomically $ writeTVar abortFlag True

  where
    doGetChar abortFlag = join $ atomically $ do
      mbC <- readTVar buf
      abort <- readTVar abortFlag
      case mbC of
        Just c ->
          do writeTVar buf Nothing; return $ callback c
        Nothing | abort -> return $ return ()
        _ -> retry
导入控制。并发
导入控制.Concurrent.STM
导入数据,也许吧
进口管制
类型Buffer=TVar(可能是Char)
launchIOThread::IO缓冲区
launchIOThread=do

buf即使我们假设
getChar
没有引发异常,问题仍然存在,因此
with mvar
没有帮助。谢谢!STM和全局缓冲区在这里不可避免吗?您认为,
getChar
也可以在
IO
中定义,而不影响其语义吗?编辑:我想是的,因为
IO
可能有全局状态。我想知道为什么
getChar':(Char->IO())->IO(IO())
不在
Prelude
System.IO
中,它有简单的语义,而且似乎无法用现有的构造进行定义(我的意思是没有
缓冲区
参数)。是的,Haskell.2中有创建全局变量的方法。前奏曲是一个模块,就像其他模块一样。把它放在序曲中并不能使它变得神奇。也许您的意思是为什么GHC自己的IO系统不提供此功能。我想,没有人会费心去做。。。
import Control.Concurrent
import Control.Concurrent.STM
import Data.Maybe
import Control.Monad

type Buffer = TVar (Maybe Char)

launchIOThread :: IO Buffer
launchIOThread = do
  buf <- atomically $ newTVar Nothing
  _ <- forkIO $ ioThread buf
  return buf

ioThread :: Buffer -> IO ()
ioThread buf = loop where
  loop =
    join $ atomically $ do
      contents <- readTVar buf
      if isJust contents -- no-one has taken the character yet
        then retry -- relax
        else return $ do
          c <- getChar
          atomically $ writeTVar buf (Just c)
          loop

getChar' :: Buffer -> (Char -> IO ()) -> IO (IO ())
getChar' buf callback = do
  abortFlag <- atomically $ newTVar False

  _ <- forkIO $ doGetChar abortFlag

  return $ atomically $ writeTVar abortFlag True

  where
    doGetChar abortFlag = join $ atomically $ do
      mbC <- readTVar buf
      abort <- readTVar abortFlag
      case mbC of
        Just c ->
          do writeTVar buf Nothing; return $ callback c
        Nothing | abort -> return $ return ()
        _ -> retry