Jan. 30th, 2014

juan_gandhi: (VP)
Я уже забыл сколько лет учусь программировать понемножку.

Вы, наверное, думаете, что вы уже умеете.
Скорее всего, вы ошибаетесь.
Но это неважно.

Вот что я понял.
Теория множеств навела сильную порчу на восприятие программирования вообще.
В частности, в головах прочно сидит такая идея, что возвращать нужно число, или что-то булево, или строку какую-нибудь. Даже если функция частичная.

Ну типа мы "память экономим". У нас 4 миллиарда байтов как минимум; мы наэкономим тыщу. Или даже миллион. Это бред; это преданья старины глубокой.

Теперь, если мы выкинем из головы этот бред про экономию памяти, то надо признать, что функции (частичные функции) не должны возвращать бессмысленное элементарное значение. А возвращать они должны значение, завёрнутое в специализированный контейнер.

Например, indexOf(sub: String)(s: String): SearchResult, вот как надо. Причём этот SearchResult не должен иметь метода, возвращающего этот самый индекс. Ниже я расскажу, что получается, если он такой метод имеет. Нет, вместо этого, надо писать что-нибудь вроде
indexOf(needle)(haystack) match {
  case FoundAt(i) => println(s"Hurray, we found it at $i!!!")
  case NotFound(what, where) => println(s"Oops, we tried to find <<$what>> in <<$where>>, but we failed. Oops.")
}


На хаскеле народ так и пишет, не задумываясь. Да и везде, где патерн-матчинг есть.

Тем не менее, популярна т.наз. монада Maybe, aka Option. У Option[T] в скале есть метод get. Недаром там параметр типа стоит; а то нафиг бы он был нужен.

Вот что такое этот get - это естественное преобразование функтора Option в функтор Exception - и всё.

Надо нам это? Кому-то надо, но я убедился (сегодня утром), что мне лично это не надо.

И вообще, использование этих мейбеев, опшенов, боксов, моего класса Result - практика порочная; это практически то же самое, что и использование примитивных типов и "кодов результата" отдельно от результата. Типы же есть! Типы! Их и надо использовать.

А, вот пример:

До
  def getOutOfPocketData:Props = {
    val tag = // redacted
    if (!loadPage(urlOfOutOfPocketPage)) {
      suspiciousError(s"Failed to load $urlOfOutOfPocketPage")
      NoProps
    } else if (!waitSelector(tag)) {
      suspiciousError("sFailed to fine $tag on $urlOutOfPocketPage")
      NoProps
    } else {
      val rawHtml = runJS(s"return document.querySelector('$tag').innerHTML")
      if (rawHtml.isBad) {
        suspiciousError(s"Failed to retrieve OOP: $rawHtml")
        NoProps
      } else {
        val html = rawHtml().toString
        val props = extractOopFrom(html)
//        debug(s"Got Props\n$props\n................... from\n$html\n=========")
        if (props.isEmpty) warn(s"Source was $html")
        props
      }
    }
  }

(проверяем сорс, парсить нечего, пишем в лог, возвращаем коллекцию пустых пропертей ("разбирайтесь мол")

после
  def getOutOfPocketData:HtmlContentParser.ParseResult = {
    val tag = // redacted
    if (!loadPage(urlOfOutOfPocketPage)) NothingToParse(s"Failed to load $urlOfOutOfPocketPage")
    else if (!waitSelector(tag)) NothingToParse("sFailed to find $tag on $urlOutOfPocketPage")
    else {
      val rawHtml = runJS(s"return document.querySelector('$tag').innerHTML")
      rawHtml fold(source => extractOopFrom(source.toString()), bad => NothingToParse(s"Failed to retrieve OOP: ${bad.mkString}")
    }
  }

(проверяем сорс, парсить нечего, возвращаем именно это состояние - результата нету! (никаких пропертей))
juan_gandhi: (VP)
The stuff I wrote earlier today kind of invalidates the need of monads on many occasions.
Just replaced <*>, tensor product of two applicatives, with match/cases
juan_gandhi: (VP)
..."первое причастие" и "второе причастие".
Дык.

Profile

juan_gandhi: (Default)
Juan-Carlos Gandhi

August 2025

S M T W T F S
      12
3456789
10 11 12 13141516
171819 20212223
24252627282930
31      

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Aug. 26th, 2025 02:38 am
Powered by Dreamwidth Studios