0

我有一个类型的 ConduitConduit a m a和一个类型的函数(a -> Maybe a)。我想运行该函数,然后如果它返回 Nothing,请使用 Conduit。也就是说,我想要一个类型的函数

maybePipe :: Conduit a m b -> (a -> Maybe b) -> Conduit a m b

或者,更受限制的类型

maybePipe :: Conduit a m a -> (a -> Maybe a) -> Conduit a m a

如果有帮助,我的具体情况如下:

我正在编写处理 IRC 消息的代码,并且我有一个函数:

runClient :: Conduit IRC.Message IO IRC.Message -> ClientSettings -> IO ()
runClient pipe address = runTCPClient' pipe' address where
    pipe' = mapC IRC.decode $= concatMapC id $= pipe $= mapC IRC.encode $= mapC (++ "\r\n")
    handlePings (IRC.Message (Just (IRC.Server serverName)) "PING" []) = Just $ IRC.pong serverName
    handlePings (IRC.Message Nothing "PING" [server]) = Just $ IRC.pong server
    handlePings (IRC.Message Nothing "PING" []) = Just $ IRC.pong (getHost address)
    handlePings _ = Nothing
    runTCPClient' :: Conduit ByteString IO ByteString -> ClientSettings -> IO ()
    runTCPClient' pipe address = runTCPClient address runClient where
        runClient appdata = appSource appdata $= linesUnboundedAsciiC $= pipe $$ appSink appdata

我希望能够maybePipe handlePings pipe在该函数中执行(或等效)操作,因此当 IRC 消息是 ping 时,我们以 pong 响应并且不调用用户指定的 Conduit。

4

2 回答 2

2

搜索 Hoogle揭示了一个几乎完全具有该类型签名的函数:mapOutputMaybe。但更惯用的方式是与Data.Conduit.List.mapMaybe.

编辑

从头开始,我明白你现在在问什么。不,没有内置组合器。但是很容易建立一个:

myHelper onNothing f = awaitForever $ maybe onNothing yield . f
于 2014-06-05T02:59:27.113 回答
0

使用 Michael 的组合器只调用(a -> Maybe b)它到达英亩的第一个项目,然后让onNothing管道接管。这不是我想要的。

相反,ZipConduit在我的具体示例中使用 , (使用conduit-combinators):

pingHandlingPipe = 
  getZipConduit $ ZipConduit (concatMapC handlePings) 
               *> ZipConduit (takeWhileC (not.isJust.handlePings) $= pipe)

或者,广义的

pipeMaybe maybeF pipe = 
  getZipConduit $ ZipConduit (concatMapC maybeF)
               *> ZipConduit (takeWhileC (not.isJust.maybeF) $= pipe)

不幸的是,这会调用该(a -> Maybe b)函数两次。

于 2014-06-05T06:39:57.900 回答