Чисто функциональная структура данных - Purely functional data structure

В Информатика, а чисто функциональная структура данных это структура данных что может быть реализовано в чисто функциональный язык. Основное отличие произвольной структуры данных от чисто функциональной заключается в том, что последняя (сильно) неизменный. Это ограничение гарантирует, что структура данных обладает преимуществами неизменяемых объектов: (полностью) настойчивость, быстрое копирование объектов и безопасность потоков. Эффективные чисто функциональные структуры данных могут потребовать использования ленивая оценка и мемоизация.

Определение

Постоянные структуры данных имеют свойство сохранять предыдущие версии без изменений. С другой стороны, такие структуры, как массивы признаться разрушительное обновление,[1] то есть обновление, которое нельзя отменить. Как только программа записывает значение в некоторый индекс массива, ее предыдущее значение больше не может быть получено.[нужна цитата ]

Формально Чисто функциональная структура данных это структура данных, которая может быть реализована в чисто функциональный язык, Такие как Haskell. На практике это означает, что структуры данных должны быть построены с использованием только постоянных структур данных, таких как кортежи, типы сумм, виды продукции, а также основные типы, такие как целые числа, символы, строки. Такая структура данных обязательно постоянна. Однако все постоянные структуры данных не являются чисто функциональными.[1]:16 Например, постоянный массив - это постоянная структура данных, реализованная с использованием массива, поэтому она не является чисто функциональной.[нужна цитата ]

В книге Чисто функциональные структуры данных, Окасаки сравнивает разрушительные обновления с ножами шеф-повара.[1]:2 Деструктивные обновления нельзя отменить, и поэтому их нельзя использовать, если нет уверенности, что предыдущее значение больше не требуется. Однако деструктивные обновления также могут обеспечить эффективность, которую нельзя получить с помощью других методов. Например, структура данных, использующая массив и деструктивные обновления, может быть заменена аналогичной структурой данных, в которой массив заменен на карта, список произвольного доступа или сбалансированное дерево, допускающий чисто функциональную реализацию. Но стоимость доступа может увеличиваться с постоянного времени до логарифмическое время.[нужна цитата ]

Обеспечение чисто функциональной структуры данных

Структура данных никогда не бывает функциональной по своей сути. Например, стек может быть реализован как односвязный список. Эта реализация является чисто функциональной до тех пор, пока единственные операции в стеке возвращают новый стек без изменения старого стека. Однако, если язык не является чисто функциональным, система времени выполнения может быть не в состоянии гарантировать неизменность. Это иллюстрирует Окасаки,[1]:9-11 где он показывает, что объединение двух односвязных списков все еще может быть выполнено с использованием императивной настройки.[нужна цитата ]

Чтобы гарантировать, что структура данных используется чисто функциональным образом на нечистом функциональном языке, модули или же классы может использоваться для обеспечения манипуляции только авторизованными функциями.[нужна цитата ]

Использование чисто функциональных структур данных

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

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

Примеры

Вот список абстрактных структур данных с чисто функциональными реализациями:

Дизайн и реализация

В его книге Чисто функциональные структуры данных, специалист в области информатики Крис Окасаки описывает методы, используемые для разработки и реализации чисто функциональных структур данных, небольшая часть которых кратко описана ниже.

Лень и запоминание

Ленивое вычисление особенно интересно на чисто функциональном языке[1]:31 потому что порядок оценки никогда не изменяет результат функции. Поэтому ленивое вычисление естественно становится важной частью построения чисто функциональных структур данных. Он позволяет производить вычисления только тогда, когда их результат действительно требуется. Следовательно, код чисто функциональной структуры данных может без потери эффективности рассматривать данные, которые будут эффективно использоваться, и данные, которые будут игнорироваться. Единственное необходимое вычисление - это первый тип данных, который будет фактически выполняться.[нужна цитата ]

Мемоизация - один из ключевых инструментов построения эффективных чисто функциональных структур данных.[1]:31 Когда вычисление выполнено, оно сохраняется, и его не нужно выполнять второй раз. Это особенно важно в ленивых реализациях; дополнительные оценки могут потребовать того же результата, но невозможно знать, какая оценка потребует этого в первую очередь.[нужна цитата ]

Амортизированный анализ и календарное планирование

Некоторые структуры данных, даже те, которые не являются чисто функциональными, например динамические массивы, допускают операции, которые эффективны большую часть времени (т. е. постоянное время для динамических массивов) и редко неэффективны (т. е. линейное время для динамических массивов). Амортизация затем можно использовать для доказательства того, что среднее время выполнения операций является эффективным.[1]:39 То есть несколько неэффективных операций достаточно редки и не меняют асимптотическую эволюцию временной сложности, когда рассматривается последовательность операций.[нужна цитата ]

В общем, наличие неэффективных операций неприемлемо для постоянных структур данных, потому что сама эта операция может вызываться много раз. Это неприемлемо ни для систем реального времени, ни для обязательных систем, где пользователю может потребоваться, чтобы время, затрачиваемое на выполнение операции, было предсказуемым. Кроме того, эта непредсказуемость усложняет использование параллелизм.[1]:83[нужна цитата ]

Чтобы избежать этих проблем, некоторые структуры данных позволяют отложить неэффективную операцию - это называется планирование.[1]:84 Единственное требование - вычисление неэффективной операции должно завершаться до того, как ее результат действительно понадобится. Постоянная часть неэффективной операции выполняется одновременно со следующим вызовом эффективной операции, так что неэффективная операция уже полностью выполнена, когда она необходима, и каждая отдельная операция остается эффективной.[требуется разъяснение ]

Пример: очередь

Амортизированные очереди[1]:65[1]:73 состоят из двух односвязных списков: передний и обратный задний. Элементы добавляются в задний список и удаляются из переднего списка. Кроме того, всякий раз, когда передняя очередь пуста, задняя очередь переворачивается и становится передней, а задняя очередь становится пустой. Амортизированная временная сложность каждой операции постоянна. Каждая ячейка списка добавляется, переворачивается и удаляется не более одного раза. Чтобы избежать неэффективной работы, когда задний список перевернут, очереди в реальном времени добавить ограничение, согласно которому длина заднего списка равна длине переднего списка. Чтобы задний список стал длиннее, чем передний, передний список добавляется к заднему списку и переворачивается. Поскольку эта операция неэффективна, она не выполняется сразу. Вместо этого он выполняется для каждой из операций. Таким образом, каждая ячейка вычисляется до того, как она понадобится, и новый передний список полностью вычисляется до того, как потребуется вызвать новую неэффективную операцию.[нужна цитата ]

Смотрите также

Рекомендации

  1. ^ а б c d е ж грамм час я j k Чисто функциональные структуры данных к Крис Окасаки, Издательство Кембриджского университета, 1998, ISBN  0-521-66350-4

внешняя ссылка