我'm trying to write a webscraper using Pipes and I'已经到了以下抓链接的部分 . 我有一个 process
函数,可以下载网址,查找链接并生成链接 .
process :: Pipe Item Item (StateT CState IO) ()
....
for (each links) yield
....
现在我想要一些如何递归地跟随这些链接,穿过StateT . 我意识到可能会做一些更惯用的事情,然后使用单个管道来处理大量的刮刀(特别是当我开始添加更多功能时),我愿意接受建议 . 当我考虑多线程w /共享状态时,我可能不得不重新考虑设计 .
2 回答
我会这样做:
您可以根据
url'
与urls
的组合方式实现DFS或BFS .您可以通过
m
参数将Pipe a b m r
连接到副作用,该参数交换管道正在操作的Monad
. 您可以使用此方法通过将管道的下游端连接到另一个管道来重新排列链接,该管道将链接粘贴在队列中,并将管道的上游端连接到从队列中读取链接的管道 .我们的目标是写作
我们将使用一个管道,其下游输出
Either l b
要么Left l
要向上游发送,要么Right b
要向下游发送,然后将l
发送回上行输入Either l a
,这是排队的Left l
或Right a
即将到来从上游 . 我们将Left l
连接在一起,形成一个只能看到来自上游的a
的管道,只会产生下行的b
.在下游端,我们将
l
从Left l
推到堆栈上 . 我们yield
r
来自Right r
下游 .在上游端,我们将在堆栈顶部寻找
yield
. 如果没有't one, we' llawait
来自上游和yield
它的值 .现在我们可以写
loopLeft
. 我们将上游和下游管道与管道组成popLeft >-> hoist lift p >-> pushLeft
组合在一起 .hoist lift
将Pipe a b m r
变成Pipe a b (t m) r
. distribute将Pipe a b (t m) r
变成t (Pipe a b m) r
. 为了回到Pipe a b m r
,我们以空堆栈[]
开始运行整个StateT
计算 . 在Pipes.Lift
中,对于evalStateT
和distribute
的组合,有一个很好的名称evalStateP .