我在多年的面向对象方面学习Haskell。如何在Haskell中设计具有状态的“web蜘蛛”?
我正在写一个功能和状态很少的哑蜘蛛。
我不知道如何在FP世界中做到这一点。
在OOP的世界这种蜘蛛可以这样设计(用法):
Browser b = new Browser()
b.goto(“http://www.google.com/”)
String firstLink = b.getLinks()[0]
b.goto(firstLink)
print(b.getHtml())
此代码加载http://www.google.com/,然后“点击”的第一个环节,第二个页面的加载内容,然后打印的内容。
class Browser {
goto(url: String) : void // loads HTML from given URL, blocking
getUrl() : String // returns current URL
getHtml() : String // returns current HTML
getLinks(): [String] // parses current HTML and returns a list of available links (URLs)
private _currentUrl:String
private _currentHtml:String
}
这是possbile有2或“浏览器”一次,有自己独立的状态:
Browser b1 = new Browser()
Browser b2 = new Browser()
b1.goto(“http://www.google.com/”)
b2.goto(“http://www.stackoverflow.com/”)
print(b1.getHtml())
print(b2.getHtml())
问题:表明你将如何在Haskell从scracth设计这样的事情(浏览器类似的API可能有几个独立的实例)?请给出一个代码片段。
注意:为了简单起见,跳过getLinks()函数的细节(它的微不足道和不感兴趣)。
也让我们假设有打开HTTP连接,并返回给定的URL的HTML API函数
getUrlContents :: String -> IO String
。
UPDATE:为什么有状态(或可能不)?
该API可以有更多的功能,而不仅仅是单一的“加载和解析结果”。
我没有添加它们来避免复杂性。
此外,它可以通过向每个请求发送HTTP Referer头和Cookie来模拟真实的浏览器行为。
考虑以下情形:
- 打开http://www.google.com/
- 类型 “哈斯克尔” 为第一输入区域
- 点击按钮 “谷歌搜索”
- 点击链接 “2”
- 点击链接“3”
- 打印当前页面的HTML(谷歌结果第3页,用于“haskell”)
有动手这样的情况下,我作为一个开发者想转让其尽可能接近的代码:
Browser b = new Browser()
b.goto("http://www.google.com/")
b.typeIntoInput(0, "haskell")
b.clickButton("Google Search") // b.goto(b.finButton("Google Search"))
b.clickLink("2") // b.goto(b.findLink("2"))
b.clickLink("3")
print(b.getHtml())
此方案的目的是后能得到最后一页的HTML一组操作。 另一个不太明显的目标是保持代码紧凑。
如果浏览器有一个状态,它可以发送HTTP Referer头和cookie,同时隐藏所有机制并提供良好的API。
如果浏览器没有状态,开发人员可能会传递所有当前的URL/HTML/Cookies - 这会给场景代码增加噪音。
注意:我猜Haskell中存在用于报废HTML的库,但我的目的不是要废除HTML,而是要了解如何在Haskell中正确设计这些“黑盒子”的东西。
辉煌。 ... – oshyshko 2010-02-22 00:37:40
请注意,BrowserAction monad已经存在:http://hackage.haskell.org/packages/archive/HTTP/4000.0.8/doc/html/Network-Browser.html – jrockway 2010-02-24 04:57:51
另请注意,'flip mapM'被称为'forM'。 – BMeph 2010-07-12 05:56:32