我有一个Conduit 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。
答案 0 :(得分:2)
Searching Hoogle会显示一个几乎完全符合该类型签名的函数:mapOutputMaybe。但更惯用的方式是融合Data.Conduit.List.mapMaybe
。
修改强>
抓一点,我明白你现在在问什么。不,没有内置的组合器。但建立一个很容易:
myHelper onNothing f = awaitForever $ maybe onNothing yield . f
答案 1 :(得分: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)
函数。