Почему мы используем постоянные структуры данных в функциональном программировании?

22

Функциональное программирование использует постоянные структуры данных и неизменные объекты. Мой вопрос: почему важно иметь такие структуры данных здесь? Я хочу понять на низком уровне, что произойдет, если структура данных не является постоянной? Будет ли программа зависать чаще?

gpuguy
источник
в abelson & sussman обсуждается довольно хорошее расширенное обсуждение структуры и интерпретации компьютерных программ
vzn

Ответы:

19

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

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

Напротив, когда вы работаете с изменяемыми объектами данных, у вас сначала возникает когнитивная нагрузка: запоминать и управлять несколькими состояниями, через которые проходит объект во время вычислений. Вы должны позаботиться о том, чтобы сделать все в правильном порядке, убедившись, что все свойства, необходимые для определенного шага, удовлетворены на этом этапе. Легко совершать ошибки, а системы типов не достаточно мощны, чтобы уловить эти ошибки.

Математика никогда не работала с изменчивыми объектами данных. Таким образом, мы не можем позаимствовать у них методы рассуждения. Есть много наших собственных методов, разработанных в области компьютерных наук, особенно Floyd-Hoare Logic . Однако освоить их сложнее, чем стандартные математические приемы, большинство студентов не могут с ними справиться и поэтому их редко обучают.

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

Удай Редди
источник
Это имеет большой смысл для меня. Спасибо, что поделились своими PPT. Вы тоже делитесь видео-записями?
gpuguy
@gpuguy. Я не так часто использую powerpoint. Доска - моя любимая среда. Но раздаточные материалы должны быть вполне читабельны сами по себе.
Uday Reddy
+1 Математика никогда не работала с изменчивыми объектами данных. Также ссылка на ваши лекционные заметки.
Guy Coder
15

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

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

Почему проще использовать постоянные структуры данных? Потому что люди действительно плохо отслеживают псевдонимы и другие неожиданные взаимодействия между различными частями программы. Они автоматически думают, что, потому что две вещи называются xи y, то не имеют ничего общего. Прежде всего, нужно понять, что «утренняя звезда» и «вечерняя звезда» - это одно и то же. Точно так же очень легко забыть о том, что структура данных может измениться, потому что с ней работают другие потоки, или потому что мы вызвали метод, который может изменить структуру данных и т. Д. Многие из этих проблем просто отсутствуют, когда мы работаем с постоянные структуры данных.

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

Андрей Бауэр
источник
если у него так много преимуществ, почему бы не использовать постоянную структуру данных и в императивных языках?
gpuguy
4
Возможно, скоро вы спросите: «Зачем использовать императивные языки?»
Андрей Бауэр
4
А если серьезно, существуют структуры данных, которые трудно заменить постоянными, например, программы обработки чисел, которые используют массивы и матрицы, намного быстрее с традиционными структурами данных, потому что оборудование оптимизировано для такого рода вещей.
Андрей Бауэр
1
@gpuguy. Постоянные структуры данных могут и должны использоваться также в императивных языках, когда они применимы и пригодны. Чтобы их можно было использовать, язык должен поддерживать управление памятью на основе сборки мусора. Это есть во многих современных языках: Java, C #, Scala, Python, Ruby, Javascript и т. Д.
Uday Reddy
Возможно, одним большим преимуществом является более абстрактный интерфейс по сравнению с изменяемыми структурами данных. Вы можете изменить вещи под капотом (см. Неизменность против целостности), но не обязаны.
Рафаэль
2

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

Это чрезвычайно полезно в области формальных методов.
Например:

  • Формальные доказательства в верификации программы упрощены с помощью расширенной статической проверки;
  • Ряд свойств из реляционной алгебры полезен при решении SAT с помощью таких инструментов, как Alloy;
  • Galois Connections допускают вычислительный подход к спецификации программного обеспечения, как показано в этом блоге , со ссылкой на статью Шин-Ченг Му и Хосе Нуно Оливейра.
  • Соединения Galois (и функциональное программирование) могут использоваться в режиме «Дизайн по контракту», поскольку они являются более общей концепцией, чем Hoare Logic.

пример

Тройка Хоара может быть выражена как контракт , где{p}P{q}[P]ϕpϕq[P]

  • [P]P
  • ϕpϕq)pq

Этот подход также позволяет рассчитывать самые слабые предварительные условия и самые сильные после условия , что полезно в ряде ситуаций.

afsantos
источник
2

Я хочу понять на низком уровне, что произойдет, если структура данных не является постоянной?

Давайте рассмотрим генератор псевдослучайных чисел с огромным пространством состояний (например, « твистер Мерсенна » с состоянием 2450 байт) в качестве структуры данных. На самом деле мы не хотим использовать какое-либо случайное число более одного раза, поэтому, похоже, нет особых оснований для реализации этого в качестве неизменяемой постоянной структуры данных. Теперь давайте спросим себя, что может пойти не так в следующем коде:

mt_gen = CreateMersenneTwisterPRNGen(seed)
integral = MonteCarloIntegral_Bulk(mt_gen) + MonteCarloIntegral_Boundary(mt_gen)

Большинство языков программирования не указывают порядок, в котором MonteCarloIntegral_Bulkи MonteCarloIntegral_Boundaryбудут оцениваться. Если оба принимают в качестве аргумента ссылку на изменяемый mt_gen, результат этого вычисления может зависеть от платформы. Что еще хуже, могут быть платформы, на которых результат не воспроизводится между разными прогонами.

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

Невоспроизводимости можно избежать, применяя фиксированный порядок последовательного выполнения. Но в этом случае код можно расположить так, чтобы в любой момент времени была доступна только одна ссылка на mt_gen. В типизированном функциональном языке программирования для обеспечения этого ограничения могут использоваться типы уникальности, что обеспечивает безопасные изменяемые обновления также в контексте чисто функциональных языков программирования. Все это может звучать красиво и модно, но по крайней мере в теории симуляции Монте-Карло смущающе параллельныи наше «решение» просто уничтожило это свойство. Это не просто теоретическая проблема, но очень реальная практическая проблема. Однако мы должны изменить (функциональность, предлагаемую) наш генератор псевдослучайных чисел и последовательность генерируемых им случайных чисел, и никакой язык программирования не может сделать это автоматически для нас. (Конечно, мы можем использовать другую библиотеку псевдослучайных чисел, которая уже предлагает необходимую функциональность.)

На низком уровне изменяемые структуры данных легко приводят к невоспроизводимости (и, следовательно, к нечистоте), если порядок выполнения не является последовательным и фиксированным. Типичная императивная стратегия для решения этих проблем состоит в том, чтобы иметь последовательные фазы с фиксированным порядком выполнения, во время которых изменяются структуры данных, и параллельные фазы с произвольным порядком выполнения, в течение которых все совместно изменяемые структуры данных остаются постоянными.


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

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


Удай Редди поднял вопрос о том, что математика никогда не работала с изменяемыми объектами данных и что системы типов для функциональных программ хорошо разработаны для неизменных объектов данных. Это напомнило мне объяснение Жана-Ива Жирара о том, что математика не используется для работы со сменными объектами, когда он пытается мотивировать линейную логику.

Кто-то может спросить, как расширить систему типов и логическую структуру функциональных языков программирования, чтобы позволить «безопасно» работать с «эффективными» изменчивыми неперспективными структурами данных. Одной из проблем здесь может быть то, что классическая логика и булевы алгебры могут быть не самой лучшей логической структурой для работы с изменчивыми структурами данных. Возможно, линейная логика и коммутативные моноиды лучше подходят для этой задачи? Возможно, мне следует прочитать то, что сказал Филипп Вадлер о линейной логике как системе типов для функциональных языков программирования? Но даже если линейная логика не сможет решить эту проблему, это не означает, что система типов и логическая структура функционального языка программирования не могут быть расширены для обеспечения «безопасности» и «эффективности».

Томас Климпел
источник
@DW Вы, вероятно, правы, что этот ответ не является отдельным ответом. В настоящее время он распространяется только на некоторые моменты, поднятые в ответах Удай Редди и Андрея Бауэра. Я думаю, что могу изменить его так, чтобы он был автономным и прямо отвечал: «Я хочу на низком уровне понять, что произойдет, если структура данных не будет постоянной»? часть вопроса. Я бы посмотрел на генератор псевдослучайных чисел с огромным пространством состояний (например, «твистер Мерсенна» с состоянием 2450 байт) в качестве структуры данных и объяснил, что может пойти не так.
Томас Климпел
@ DW Я не чувствую, что какой-либо из ответов на этот вопрос действительно отвечает на вопрос. В частности, нет ничего особенного в том, что в действительности представляют собой постоянные структуры данных (кроме того, что они являются неизменяемыми) и как они реализуются.
Гильденстерн