我目前正在编写一个程序来分析从多个tar档案中收集的文件。我使用的是conduit
,相关代码是here。这是一个示例计算:
unixVersion :: Require T.Text BSL.ByteString UnixVersion
unixVersion = (parseRedhat <$> requireText "/etc/redhat-release")
<|> (parseSuse <$> requireText "/etc/SuSE-release")
<|> ....
目标是每次越过相关的流事件时,所有这些计算都会“高级”(在前面的示例中,这将是与/etc/redhat-release
或/etc/SuSE-release
对应的tar条目。)< / p>
使用这种功能的“完整”示例可能是:
tarStream "/path/to/tar.gz" =$ withRequirement [listcve] fst snd
=$ CL.concat
$$ CL.consume
与
-- given the version of an OS and a list of installed packages, gives the CVEs
-- affecting this host.
listcve :: Require FilePath BSL.ByteString [CVE]
listcve = listCVEs <$> (cvelist <$> unixVersion)
<*> (T.lines <$> requireText "/soft/packages.lst")
where
listCVEs cvelist packages = ....
cvelist v = case v of
REDHAT -> redhatCVEs
_ -> defaultCVEs
这个人为的例子只有一个计算,但我的最终程序将有大约30个,有几个“共享”计算(如unixVersion
)。为了实现这一点,我决定我需要一种方法来知道流的给定元素是否容易被这些Require
计算中的一个请求。这意味着我需要一个像:
getRequirements :: Require a b c -> S.Set a
不幸的是,这可能意味着Require a b
最多只能是Applicative
,永远不会是Monad
。
然后有withRequirement
函数,其类型为:
withRequirement :: (Ord identifier, Eq identifier, Monad m)
=> [Require identifier content x] -- ^ The list of dependent computations
-> (a -> identifier) -- ^ Extracting the identifier
-> (a -> m content) -- ^ Extracting the content, possibly with effects
-> Conduit a m x
这就像需求列表中的解释器一样。
无论如何,这是我的问题:
unixVersion
分析器被其他几个分析仪使用。在我目前的实现中,它们为每个实现重新计算。Monad
接口,但不要尝试为每个流条目运行每个分析器?