0

私が抱えているエラーに加えて、私がやっていることがどれほどひどいかについてのヒントをいただければ幸いです。

コードを貼り付けます。しかし、それはほとんど正しいと思います.forkFinallyに型チェックをさせることができません...

エラーは、forkFinally を呼び出す唯一の行にあります。

Ambiguous type variable `e0' in the constraint:
  (Exception e0) arising from a use of `forkFinally'
Probable fix: add a type signature that fixes these type variable(s)
In a stmt of a 'do' block:
  t <- forkFinally (echoHandler a) (exitPool p)
In the expression:
  do { a <- accept s;
       t <- forkFinally (echoHandler a) (exitPool p);
       atomically
       $ do { p' <- readTVar p;
              writeTVar p (t : p') };
       repeatAccept s p }
In an equation for `repeatAccept':
    repeatAccept s p
      = do { a <- accept s;
             t <- forkFinally (echoHandler a) (exitPool p);
             atomically
             $ do { p' <- readTVar p;
                    .... };
             .... } Failed, modules loaded: none.

コードは次のとおりです。

type ConnectionHandler = (Handle, HostName, PortNumber) -> IO ()
type Pool = TVar [ThreadId]

runConn = do
  s <- withSocketsDo (listenOn (PortNumber 1234))
  p <- atomically (newTVar ([]::[ThreadId]))
  t <- forkIO (repeatAccept s p)
  repeatUntilExit stdin stdout putChar ""
  p' <- atomically (readTVar p)
  mapM killThread (t:p')

repeatAccept s p = do
  a <- accept s
  t <- forkFinally (echoHandler a) (exitPool p) -- Error here, forkIO instead compiles fine.. (and I guess actually should work just fine too?)
  atomically $ do
    p' <- readTVar p
    writeTVar p (t:p')
  repeatAccept s p

exitPool :: Pool -> a -> IO ()
exitPool pool = \_ -> do
  tid <- myThreadId
  atomically $ do
    pool' <- readTVar pool
    writeTVar pool $ filter (/=tid) pool'
    return ()

echoHandler :: ConnectionHandler
echoHandler a@(hdl,_,_) = repeatUntilExit hdl hdl echoToHandleAndStdout ""
  where echoToHandleAndStdout x = hPutChar hdl x >> putChar x

repeatUntilExit :: Handle -> Handle -> (Char -> IO ()) -> [Char] -> IO ()
repeatUntilExit hIn hOut f "exit\n" = hPutStrLn hOut "bye\n"
repeatUntilExit hIn hOut f x = hGetChar hIn >>= \c -> f c >> repeatUntilExit hIn hOut f (appendToLastFive c)
  where appendToLastFive a = (reverse . (:)a . take 4 . reverse) x

forkFinally :: Exception e => IO a -> (Either e a -> IO ()) -> IO ThreadId
forkFinally action and_then =
  mask $ \restore ->
    forkIO $ try (restore action) >>= and_then
4

1 に答える 1

6

forkFinally最新の Control.Concurrent の署名を入力します。

forkFinally :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId

コードに署名を入力forkFinallyします。

forkFinally :: Exception e => IO a -> (Either e a -> IO ()) -> IO ThreadId

例外タイプを一般化しようとしました。forkFinallyの 2 番目のパラメーターから例外の種類を推測できる場合、これは問題ではありません。しかし、これはforkFinallyの 2 番目のパラメーターです。

exitPool p :: a' -> IO ()

型チェッカーは と統合しようとしEither e a -> IO ()ますが、何がa' -> IO ()何でeあるかを推測できなくなります。

一般的な解決策: 明示的な型を指定します。例えば

t <- forkFinally (echoHandler a) (exitPool p :: Either SomeException () -> IO ())

より具体的な解決策: 元の型シグネチャを に復元しforkFinallyます。限られた例外セットのみをキャッチするのは意味がないようです。

于 2013-03-14T21:42:23.377 に答える