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