Помогите мне понять, как конфликт между неизменяемостью и временем выполнения обрабатывается в Clojure - PullRequest
3 голосов
/ 10 сентября 2010

Clojure действительно пробудил во мне интерес, и я начал изучать его: http://java.ociweb.com/mark/clojure/article.html

Рассмотрим две строки, упомянутые в разделе «Набор»:

(def stooges (hash-set "Moe" "Larry" "Curly")) ; not sorted
(def more-stooges (conj stooges "Shemp")) ; -> #{"Moe" "Larry" "Curly" "Shemp"}

Моя первая мысльбыло то, что вторая операция должна занять постоянное время для завершения;в противном случае функциональный язык может иметь мало преимуществ по сравнению с объектно-ориентированным языком.Можно легко представить, что нужно начинать с [почти] пустого набора, заполнять его и уменьшать по мере продвижения вперед.Таким образом, вместо того, чтобы назначать новый результат большему количеству хранилищ, мы могли бы переназначить его себе.

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

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

Приведенные выше примеры могут показаться не очень практичными или иметь обходные пути, но объектно-ориентированный язык, такой как Java / C # / Python / и т. Д.не имеет проблем ни с увеличением, ни с уменьшением набора одного или нескольких элементов одновременно, а также с быстрым выполнением.

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

Для кого-то, знакомого с Python, я бы упомянул понимание набора по сравнению с подходом эквивалентного цикла.Время работы обоих немного отличается, но это связано с относительными скоростями C, Python, интерпретатором и не имеет корней в сложности.Проблема, которую я вижу, состоит в том, что понимание набора является часто лучшим подходом, но НЕ ВСЕГДА лучшим подходом, поскольку читаемость может сильно пострадать.

Позвольте мнезнать, если вопрос не ясен.

Ответы [ 2 ]

8 голосов
/ 10 сентября 2010

Основные неизменяемые структуры данных - одна из самых интересных частей языка для меня. Их ответ на этот вопрос очень важен, и Рич действительно отлично справляется с этим в этом видео:

http://blip.tv/file/707974

Основные структуры данных:

  • фактически полностью неизменны
  • старые копии также неизменны
  • производительность не ухудшается для старых копий
  • доступ постоянный (фактически ограниченный <= постоянная) </li>
  • все поддерживают эффективное добавление, объединение (кроме списков и последовательностей) и прерывание

Как они это делают ???

  • секрет: это почти все деревья под капотом (на самом деле трия).

Но что, если я действительно хочу что-то редактировать на месте?

  • вы можете использовать переходные процессы clojure , чтобы редактировать структуру на месте и затем создавать неизменяемую версию (в постоянном времени), когда вы готовы поделиться ею.

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

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

Я действительно рекомендую (относительно короткую) _ книгу: Чисто функциональные структуры данных В нем он охватывает множество действительно интересных структур и концепций, таких как «снятие амортизации», чтобы обеспечить истинный постоянный доступ ко всем очередям. и такие вещи, как ленивые постоянные очереди. Автор даже предлагает бесплатную копию в pdf здесь

3 голосов
/ 10 сентября 2010

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

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

Эти сообщения , а также некоторые из выступлений Рича Хики , дают хороший обзор реализации постоянных структур данных.

...