Я изучаю Haskell после многих лет ООП.
Я пишу немой веб-паук с несколькими функциями и состоянием.
Я не уверен, как сделать это правильно в мире FP.
В мире ООП этот паук может быть спроектирован таким образом (по использованию):
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
}
Возможно наличие двух или "браузеров" одновременно со своим отдельным состоянием:
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() (ее тривиальные и не интересные). Также предположим, что есть функция API
getUrlContents :: String -> IO String
который открывает HTTP-соединение и возвращает HTML для данного URL-адреса.
ОБНОВЛЕНИЕ: зачем иметь состояние (или может быть не так)?
API может иметь больше функций, а не только отдельные "результаты загрузки и анализа".
Я не добавлял их, чтобы избежать сложности.
Также он может заботиться о заголовке HTTP-заголовка и файлах cookie, отправив их с каждым запросом, чтобы эмулировать реальное поведение браузера.
Рассмотрим следующий сценарий:
- Откройте http://www.google.com/
- Введите "haskell" в первую область ввода
- Нажмите кнопку "Поиск Google"
- Нажмите ссылку "2"
- Нажмите ссылку "3"
- Печать HTML текущей страницы (страница результатов google 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-заголовка и файлы cookie, скрывая всю механику внутри себя и предоставляя хороший API.
Если в браузере нет состояния, разработчик, скорее всего, передаст все текущие URL/HTML/Cookies - и это добавит шум в код сценария.
ПРИМЕЧАНИЕ. Я предполагаю, что существуют библиотеки для утилизации HTML в Haskell, но я не собирался отказываться от HTML, но узнал, как эти "черные ящики" могут быть правильно разработаны в Haskell.