1

さらにパイプラインを開始する前に、クライアントとの間で少し行ったり来たりして、Client オブジェクトまたはその名前文字列を取得する必要があります。

しかし、私は appSink に戻り値を持たせることができないようです。

どうすればいいですか?

checkAddClient :: Server -> ClientName -> AppData -> IO (Maybe Client)
checkAddClient server@Server{..} name app = atomically $ do
  clientmap <- readTVar clients
  if Map.member name clientmap
    then return Nothing
    else do
        client <- newClient name app
        writeTVar clients $ Map.insert name client clientmap
        return (Just client)


readName server app = go
  where
  go = do
    yield "What is your name? "
    name <- lineAsciiC $ takeCE 80 =$= filterCE (/= _cr) =$= foldC
    if BS.null name
      then go
      else do
        ok <- liftIO $ checkAddClient server name app
        case ok of
            Nothing -> do
                yield . BS.pack $ printf "The name '%s' is in use, please choose another\n" $ BS.unpack name
                go
            Just client -> do
                yield . BS.pack $ printf "Welcome, %s!\n" $ BS.unpack name
                return client -- <-- Here is the problem!!

main :: IO ()
main = do
    server <- newServer
    runTCPServer (serverSettings 4000 "*") $ \clientApp -> do
        (clientC, client) <- appSource clientApp $$+ readName server clientApp =$ appSink clientApp

アップデート

これが私が最終的に得た解決策です:

readName :: Server -> AppData -> Sink BS.ByteString IO Client
readName server app = go
  where
  go = do
    yield "What is your name? " $$ appSink app
    name <- lineAsciiC $ takeCE 80 =$= filterCE (/= _cr) =$= foldC
    if BS.null name
      then go
      else do
        ok <- liftIO $ checkAddClient server name app
        case ok of
            Nothing -> do
                yield (BS.pack $ printf "The name '%s' is in use, please choose another\n" $ BS.unpack name) $$ appSink app
                go
            Just client -> do
                yield (BS.pack $ printf "Welcome, %s!\n" $ BS.unpack name) $$ appSink app
                return client


main :: IO ()
main = do
    server <- newServer
    runTCPServer (serverSettings 4000 "*") $ \clientC -> do
        client <- appSource clientC $$ readName server clientC
        print $ clientName client
4

1 に答える 1

1

これは、プライマリ コンジット API の制限です。最も下流のコンポーネント以外から結果値を取得することはできません。いくつかの回避策があります。

  1. アップストリームのファイナライザーをキャプチャできる、より高度なコンジット API があります興味のある機能はwithUpstreamです。これは問題に対する「正しい」アプローチですが、このより高度な API が主要な API ではないのには理由があります。これには 6 つの型パラメーターがあり、人々を混乱させる傾向があります。

  2. readNameに融合する代わりに、呼び出しごとappSinkに渡しappSinkて融合します。例えば:readNameyield

    yield (BS.pack $ printf "...") $$ appSink app
    

    これはおそらく、単純さとタイプ セーフの最適なバランスです。

  3. またはその他の可変変数を作成しIORef、クライアントの名前をその可変変数に入れます。

于 2014-05-29T04:01:21.097 に答える