LINUX.ORG.RU

Алгоритмы с курсеры и ФП. Лыжи не едут или дело во мне?

 , ,


0

3

Доброго времени суток дамы и господа. Героически прохожу курсы с курсеры «Algorithms: Design and Analysis», для прохождения применяю scala. Тут достаточно много людей, проходивших этот самый курс, которые писали код заданий в функциональном стиле. Посему этим героям вопрос: как, блин?

Для тех кто не в курсе, поясню: в курсах есть задания из разряда 1) вот вам входные данные, подсчитайте результат. 2) а теперь все то же самое, только входных данных будет очень много.

И вот когда входных данных становится очень много, я смело выкидываю все эти List, map, flatten и иммутабельность, и заменяю на циклы, массивы и мутабельные данные, чтобы не состариться, пока моя реализация алгоритма чего-то там считает.

Из последнего: сколько кластеров в результате k-clustering будет, при условии что минимальное расстояние между кластерами 3.

Ну я и бахнул вот

  val COST = 3
  for(i<-Range(0,N)){
    for(j<-Range(i,N)){
      if(i!=j){
        var dif = insane(i).getDif(insane(j))
        if(dif<COST) {
          insane(i).merge(insane(j))
        }
      }
    }
  }

где megre и getParent

  def getParent = {
    var ret:Node = parent
    while(!(ret.parent eq ret)){
      ret = ret.parent
    }
    ret
  }

  def merge(an:Node){
    if(!(an.getParent eq this.getParent))
      an.getParent.parent = this
  }

Ну и как это должно выглядеть в функциональном стиле, чтобы быстро было достаточно? И литературы мне, господа просветленные.

★★★★★

Последнее исправление: RedPossum (всего исправлений: 2)

хвостовая рекурсия. В шкале для этого даже какой-то спец кейворд есть, tailrec чтоли

Bad_ptr ★★★★★
()
Ответ на: комментарий от Bad_ptr

В шкале для этого даже какой-то спец кейворд есть, tailrec чтоли

Аннотация там есть специальная, которая проверяет что метод оптимизируется хвостово. Ну так перепишу я, значит циклы рекурсией, от этого же не станет все сразу функциональным.

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от RedPossum

Ну так перепишу я, значит циклы рекурсией, от этого же не станет все сразу функциональным.

как это? Станет, станет более функционально!

Bad_ptr ★★★★★
()
Ответ на: комментарий от Bad_ptr

а иммутабельность? Вот смотри, там количество merge такое, что нет от иммутабельности никаких доходов, расходы одни. То есть все таки лыжи и тут вот применять ФП не в кассу, получается, если цели применять именно ФП не стоит.

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от Bad_ptr

insane - это такой массив интов, называется он так потому что здоровый, зараза. Node - это такая обертка c value:Int, и parent:Node(по умолчанию this). getDif - это Integer.bitCount(a^b), то есть Хэмингово расстояние между массивчиками байт.

Полный код выкладывать не хочется, потому как побанят еще.

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от anonymous

А если серьезно, то раз нужна мутабельность - используй мутабельность. Пока она контролируемая, проблем нет.

anonymous
()

Когда напишешь на сишке или йаве эффективную многопоточную реализацию списка с пропусками, тогда будешь выделываться на фп

anonymous
()
def getParent = {
  def loop(ret: Node): Node = 
    if (ret.parent eq ret) ret 
    else loop(ret.parent)

  loop(parent)
}


val COST = 3
for {
  i <- 0 until N
  j <- i until N
  if i != j
  val dif = insane(i) getDif insane(j)
  if dif < COST 
} insane(i).merge(insane(j))

чтобы merge переписать надо другое представление графа

anonymous
()
Ответ на: комментарий от anonymous

тут принципиально ничего не поменялось же.

чтобы merge переписать надо другое представление графа

это я понимаю, однако что-то в голову не лезет, как представление поменять, чтобы сильно не просела производительность.

//if i != j надо убрать, осталось от прошлых экспериментов

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от RedPossum

тут принципиально ничего не поменялось же.

Ну getParent иммутабельная теперь

это я понимаю, однако что-то в голову не лезет, как представление поменять

Вместо того, чтобы хранить parent в виде ссылки, храни значение ключа, сам массив поменяй на иммутабельное хранилище (хеш/дерево там, попробуй разные варианты). merge должна возвращать либо исходный граф, либо переделанный.

(for {
  i <- 0 until N
  j <- i until N
  if i != j
  val dif = insane(i) getDif insane(j)
  if dif < COST 
} yield (i,j)).foldLeft(graph) { case (graph, pair) => graph merge pair }
anonymous
()
Ответ на: комментарий от RedPossum

А никто и не заставляет. Scala - это чистый ООП язык с возможностями ФП.

LongLiveUbuntu ★★★★★
()

а зачем это делать в функциональном стиле? Весь алгоритм — сплошные ассайнменты, и на иммютабл объектах у тебя гарбэдж коллектор наработает больше чем сам алгоритм.

nokachi
()
Ответ на: комментарий от nokachi

А тут и не нужен константый доступ, тут и списка хватит связного.

А зачем? Да интересно стало, есть же хаскелисты, к примеру, которые этот курс проходили

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от Bad_ptr

По-хорошему там еще надо с монадическим трансформером и засунуть graph в state монадку. Но это уже будет пиздец.

anonymous
()
Ответ на: комментарий от nokachi

а зачем это делать в функциональном стиле?

для тренировки

Bad_ptr ★★★★★
()
Ответ на: комментарий от anonymous

и я о том же, смысла в имплементации алгоритма на языке предназначенном не для быстроты и экономии ресурсов — не очень много

nokachi
()
Ответ на: комментарий от anonymous

Когда напишешь на сишке или йаве эффективную многопоточную реализацию списка с пропусками, тогда будешь выделываться на фп

От простого к сложному. Сначала concurrency для слабаков - иммутабельность, ФП. А потом уже можно и перестать прикрывать свою жопу сборщиком мусора и начать писать быстрый код

vertexua ★★★★★
()
Ответ на: комментарий от vertexua

Это сильно. Особенно в performance oriented задачах

Ну не два массива и статические методы для обработки использовать в конце концов. Я так и C вспомню сдуру.

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от RedPossum

Идиоматичность и правильное абстрагирование - это для некритических к производительности задач. Для критичных - Array, while, @tailrec и вперде. А то и sun.misc.Unsafe. И да, на Scala

vertexua ★★★★★
()
Ответ на: комментарий от vertexua

Я не пытаюсь выжать максимум, хотелось бы увидеть решение с присущей фп анонистской элегантностью. Знаний для самостоятельного запила подобного мне не достаточно категорически.

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от qnikst

Сейчас хипстеры стараются писать медленный и жручий код без IO. А вычислений IO сторонятся как чего-то грязного и немытого.

dave ★★★★★
()
Ответ на: комментарий от dave

ну IO ж нужно далеко не всегда, а ещё и ST есть :), тем более в тех задачах которые решает ТС даже списков хватит :)

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

Ну, задачу ТС пусть ТС и решает, а мы тут пока потроллим. Мне бы в голову не пришло просить у кого-то помощи. Да, и по его коду вижу, что ему еще нужно учиться.

Все же, IO требуется чаще, чем этого хотелось бы некоторым. Во многих учебниках IO как-то обходится стороной, даже с некоторым пренебрежением иногда.

dave ★★★★★
()
Ответ на: комментарий от dave

Все же, IO требуется чаще, чем этого хотелось бы некоторым. Во многих учебниках IO как-то обходится стороной, даже с некоторым пренебрежением иногда.

это правильно если человек пришёл из императивного мира, а то иначе все алгоритмы к IO сведутся. :)

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

Это если есть детерминированность, на что указывал Павел Худак (или Худяк?) (Paul Hudak). Однако, не все задачи такие. Возможно сочетание недетерминированности и декларативности. Там без IO никуда.

dave ★★★★★
()
Ответ на: комментарий от qnikst

В той задаче нужно ст и списки, то есть привет монадические трансформеры, если хотип похипстерски

anonymous
()
Ответ на: комментарий от anonymous

завтра посмотрю, как можно ли сделать без ST, первое задание из курса оказалось на 30 минут, с условием чтения алгоритмов. Второе видать посложнее будет, (да, мне лень смотреть видео).

qnikst ★★★★★
()
Ответ на: комментарий от dave

Мне бы в голову не пришло просить у кого-то помощи.

да я не то чтобы помощи прошу, как всегда литературки бы, или вектор движения общий.

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от RedPossum

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

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от RedPossum

Честно говоря, не видел этих курсов, кроме там каких-то слайдов про моделирование.

С некоторых пор считаю, что для того, чтобы лучше понять стиль ФП, желательно изучить хаскель. Мне нравится несколько книг, и я бы не советовал начинать с Real World Haskell. Но это требует много времени (и практики).

Мне кажется, что можно пойти по другому пути, более быстрому. По Scala есть превосходная книга Programming in Scala в соавторстве с самим Одерским. После ее штудирования мне кажется, что курс на курсера уже не нужен, но необходима практика.

Тут такое дело. Хорошо начинать подходить к решению задачи с позиций ФП: чистые функции, иммутабельность (и прочие умные слова). Потом по мере углубления в задачу бывает полезно применять более «грязные» методы, такие как ООП и мутабельность. Быть может, этот курс преследует целью показать именно этот подход?

dave ★★★★★
()
Ответ на: комментарий от dave

Быть может, этот курс преследует целью показать именно этот подход?

Курс, из которого данная задача просто по алгоритмам и ФП не при чем.

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от dave

У Одерского в курсе было все как раз максимально просто: он рассказывал о какой-то фиче; рассказывал о задачах которые решаются такими фичами; давал задание по применению фичи.

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от RedPossum

А ты его книгу читал? Там много примеров. Можно по ней учиться.

А что касается алгоритмов, то для чистого ФП они немного другие, или даже бывают сильно другими. Но тема сложная, в двух словах не пересказать. По алгоритмам есть интересная книга «Algorithms - A Functional Programming Approach». Там в качестве языка используется хаскель (черт, как в этой макоси файлы дежавю смотреть, не прибегая к AppStore?)

dave ★★★★★
()
Ответ на: комментарий от dave

«Algorithms - A Functional Programming Approach»

Там в качестве языка используется хаскель

уровень хаскела для вхождения высокий?

RedPossum ★★★★★
() автор топика
Ответ на: комментарий от RedPossum

Нет, совсем нет. Там нормальный хаскель без загибонов. Кажется, даже монад нет (не могу проверить сейчас - если только в самом конце книги).

dave ★★★★★
()
Последнее исправление: dave (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.