【问题标题】:How can I get a value after running a conduit?运行管道后如何获得值?
【发布时间】:2014-05-28 22:22:38
【问题描述】:

在启动更多管道之前,我需要在与客户端之间来回做一些事情,并获取客户端对象或其名称字符串。

但我似乎无法让 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

【问题讨论】:

    标签: haskell conduit network-conduit


    【解决方案1】:

    这是主要管道 API 的一个限制:除了最下游的组件之外,您无法从其他任何地方获取结果值。有一些解决方法:

    1. 有一个更高级的管道 API,确实允许捕获上游终结器。您感兴趣的功能是withUpstream。请注意,这是解决问题的“正确”方法,但这个更高级的 API 不是主要的 API 是有原因的:它有六个类型参数,容易让人感到困惑。

    2. 不要将readName 融合到appSink,而是将appSink 传递到readName 并在每次yield 调用时融合它。例如:

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

      这可能是简单性和类型安全之间的最佳平衡。

    3. 创建一个IORef 或其他可变变量,并将客户端的名称放入该可变变量中。

    【讨论】:

    • 我选择了选项 #2。效果很好!感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多