Как вы пишете структуры данных, которые настолько эффективны, насколько это возможно в GHC? - программирование
Подтвердить что ты не робот

Как вы пишете структуры данных, которые настолько эффективны, насколько это возможно в GHC?

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

Однако я работаю специально с GHC. Для моих приложений важны постоянные факторы. Использование памяти также для меня очень важно. Поэтому у меня есть вопросы конкретно о GHC.

В частности,

  • Как максимизировать совместное использование узлов.
  • Как уменьшить объем памяти памяти
  • Как избежать утечек пространства из-за неправильной строгости/лени.
  • Как получить GHC для создания плотных внутренних петель для важных разделов кода.

Я просмотрел различные места в Интернете, и у меня есть смутное представление о том, как работать с GHC, например, глядя на основной вывод, используя UNPACK прагмы и т.п. Но я не уверен, что понимаю.

Итак, я открыла свою любимую библиотеку структур данных, контейнеры и посмотрел модуль Data.Sequence. Я не могу сказать, что я много понимаю, что они делают, чтобы быстро сделать Seq.

Первое, что бросается в глаза, - это определение FingerTree a. Я предполагаю, что только я не знаком с пальцами. Второе, что бросается в глаза, - это все прагмы SPECIALIZE. Я понятия не имею, что здесь происходит, и мне очень любопытно, поскольку они усеяны по всему коду.

У многих функций также есть прагма INLINE, связанная с ними. Я могу догадаться, что это значит, но как я могу судить о том, когда функции INLINE?

Вещи действительно интересны вокруг линии ~ 475, секции, которая называется "Аппликационная конструкция". Они определяют оболочку newtype для представления монады Identity, они пишут свою собственную копию монады строгого состояния, и у них есть функция, определенная под названием applicativeTree, которая, по-видимому, специализируется на Monad Identity, и это увеличивает совместное использование вывода функция. Я понятия не имею, что здесь происходит. Какое колдовство используется для увеличения обмена?

В любом случае, я не уверен, что многое можно узнать из Data.Sequence. Существуют ли другие "программные программы", которые я могу прочитать, чтобы получить мудрость? Мне очень хотелось бы знать, как сушить мои структуры данных, когда мне действительно нужно, чтобы они пошли быстрее. В частности, речь идет о создании структур данных, облегчающих слияние, и о том, как писать хорошие правила слияния.

4b9b3361

Ответ 1

Это большая тема! Большинство из них объяснено в другом месте, поэтому я не буду пытаться написать книгу. Вместо этого:

  • Real World Haskell, ch 25, " Производительность" - обсуждает профилирование, простую специализацию и распаковку, чтение Core и некоторые оптимизации.

Йохан Тибелл много пишет в этой теме:

И некоторые вещи отсюда:

И некоторые другие вещи:

Ответ 2

applicativeTree довольно причудливо, но главным образом в том, что касается, в частности, FingerTrees, которые представляют собой весьма причудливые данные сами структуры. Мы обсуждали тонкости в cstheory. Обратите внимание, что applicativeTree записывается для работы над любым аппликативным. Так получилось, что, когда он специализируется на Id, он может совместно использовать узлы таким образом, который иначе не мог. Вы можете самостоятельно работать по специализации, введя в себя методы Id и узнав, что произойдет. Обратите внимание, что эта специализация используется только в одном месте - функция O (log n) replicate. Тот факт, что более общая функция аккуратно специализируется на постоянном случае, - это очень умный бит повторного использования кода, но это действительно все.

В целом, Sequence преподает больше о разработке постоянных структур данных, чем о всех трюках для повышения производительности, я думаю. Идеи Дона, конечно, превосходны. Я также просто просмотрел источник действительно канонических и настроенных библиотек - Map, IntMap, Set и IntSet в частности. Наряду с этим стоит взглянуть на документ о своих улучшениях в контейнерах.