Haskell中带向量的动态规划

Haskell中带向量的动态规划,haskell,dynamic,vector,monads,Haskell,Dynamic,Vector,Monads,我试图用haskell编写一种简单的网络爬虫程序,只是为了练习。令我自己惊讶的是,web请求本身和解析web站点都不复杂。 我用递归函数对程序进行了纯粹的功能性编码,但仅在大约四五十个web请求之后,程序就耗尽了所有内存 所以我试着用动态规划来完成这个任务,但是我完全被卡住了,这意味着,我不知道从哪里开始。在这个小程序中,我犯了太多错误,以至于我不知道从哪里开始 这是我目前的想法: scanPage :: String -> IO (String,String,[String]) scan

我试图用haskell编写一种简单的网络爬虫程序,只是为了练习。令我自己惊讶的是,web请求本身和解析web站点都不复杂。 我用递归函数对程序进行了纯粹的功能性编码,但仅在大约四五十个web请求之后,程序就耗尽了所有内存

所以我试着用动态规划来完成这个任务,但是我完全被卡住了,这意味着,我不知道从哪里开始。在这个小程序中,我犯了太多错误,以至于我不知道从哪里开始

这是我目前的想法:

scanPage :: String -> IO (String,String,[String])
scanPage url = ....

crawler :: String -> IO [(String, Int)]
crawler startUrl = runST $ do
    toVisit <- newSTRef [startUrl] :: ST s (STRef s [String])
    visited <- newSTRef [] :: ST s (STRef s [String])
    result  <- newSTRef [] :: ST s (STRef s [(String, Int)])
    -- Iterate over urls to visit
    while (liftM not $ liftM null $ readSTRef toVisit) $ do
        url <- fmap (head) (readSTRef toVisit)            
        (moreUrls, value_a, value_b) <- scanPage url
        -- Mark page as visited
        vis <- readSTRef visited
        writeSTRef visited (url : vis)
        -- Add Results
        res <- readSTRef result
        writeSTRef result ((value_a, value_b) : res)
        -- Extend urls to visit
        nextUrls <- readSTRef toVisit
        writeSTRef toVisit (nextUrls ++ (moreUrls \\ vis))
    -- End of while
    return =<< readSTRef result

main = do
    putStrLn =<< fmap show (crawler "http://starturl.com")
编辑:
我仍然没有任何线索,如何将这个伪代码转换成真正的代码,尤其是while语句。任何值得注意的提示。

您的
访问列表的自然数据结构是一个队列。虽然有一些队列的实现,但出于这个目的,最简单的方法是只使用
Data.Sequence.Seq
。这使您可以使用
|>
将内容添加到末尾,并使用
viewl
查看开头。考虑一些类似

crawlOnce :: Seq Url -> [Url] -> IO (Either [Url] (Seq Url, [Url]))
crawlOnce to visitlist visitedList
使用
viewl
查看要访问的URL列表的前面。如果为空,则返回
左侧访问列表
。否则,它将访问第一个URL,将其附加到已访问列表中,并将新发现的URL添加到要访问的列表中,然后将它们包装在
右侧


有几个合理的变化。例如,您可以选择一种类型,如
ExceptT[Url](StateT(Seq-Url[Url])IO)a
,它“抛出”它的最终结果。

当递归函数开始占用您的所有内存时,这通常意味着它们一直在调用自己而不返回。你应该尽可能使它们尾部递归,这样它们就不会有这个问题。
控件.Monad
包在
保护
时有
,但我的直觉是,如果你还不习惯Monad,那对你来说不是最好的解决方案。事实上,我也尝试过这个方法,因此,最后一个调用返回了完整的结果,但它仍然会占用所有内存。然而,我也想了解动态方法。举个例子会很有帮助。每个中间调用都是递归的吗?如果您编写
f[]=”
f(x:xs)=(show x)++(f xs)
,则运行时只能优化基本情况。如果你写,
fxs=f'xs[]
f'[]acc=acc
f'(x:xs)acc=f'xs(acc++(show x))
,它可以清理所有的临时性。你说的“动态方法”是什么意思?序列听起来很棒。有太多的课程需要探索。。。是否有一种表或映射,包含所有按函数分组的有用类?@Hennes,对于类(此处不相关),有Typeclassopedia。对于基本库,您可能想看看Haskell平台中包含了什么,不管您是否真正决定安装该平台?我们怎样才能用队列过滤掉重复的内容?@rubik,说得好!我们可能两者都有,使用集合来表示访问列表,并使用集合来过滤添加到队列中的内容。来吧,不要让我跪在地上乞求为这项任务提供一个简单的工作示例。我真的花了整整一天的时间在谷歌上寻找帮助,但什么也没找到。了解这一切对我会有很大帮助。
toVisitList = startURL
visitedList = []
resultList = []
while (length toVisitList /= 0) {
    url = head toVisitList   -- Get the 1st element
    toVisitList -= url       -- Remove this url from list
    visitedList += url       -- Append url to visitedList
    (moreUrls, val_a, val_b) = scanPage url
    resultList += (val_a, val_b) -- append the result
    toVisitList += (moreUrls - visitedList)
}
return resultList
crawlOnce :: Seq Url -> [Url] -> IO (Either [Url] (Seq Url, [Url]))