Что бы не было скучно, я сделал вольный перевод статейки из журнала "Functional Programming" (ACM SIGPLAN). Я перевел только ключевые места. Полную статью можно найти в интернете. "Paths between Imperative and Functional Programming" Thomas Ball tball@research.bell-labs.com Предлагаю обсудить. Осуществимые и неосуществимые пути. Независимо от языка программирования, программа исполняет путь или последовательность инструкций. В императивных программах путь состоит из последовательности операторов. В функциональных программах из последовательности вычислений выражений. В программе может быть огромное число путей исполнения, но не все они осуществимы. Путь в программе называется осуществимым, если существуют такие входные данные, при которых исполнение проходит по этому пути. Неосуществимые пути появляются из-за того, что в программе могут быть кореллирующие условные переходы. Например:
В этой программе четыре пути исполнения, так как в ней два условных оператора. При этом один из путей неосуществим. Так как если x < 10, то также x < 20. Мы можем переписать программу, что бы в ней не было неосуществимых путей:
Такие изменения уменьшили сложность программы и сделали ее эффект более явным. Более сложный пример Это часть реализации алгоритма упорядоченого бинарного дерева из книги "Introduction to Algorithms", T. Cormen, C. Leiserson и R. Rivest.
Функция удаляет узел дерева, сохраняя порядок. Поиск узла, который должен встать вместо удаляемого делает функция leftmostNode.
В DeleteNode 36 путей. И только 8 из них осуществимы. Ниже одна из возможных реализаций DeleteNode.
В этой реализации всего 9 путей. Из них 8 осуществимы. Программа стала яснее, из-за того, что теперь нет ненужных зависимостей между условными операторами. Неосуществимые пути и связь императивного и функционального стиля. Вторая реализация DeleteNode более функциональна по следующим причинам: 1) Было удалено большинство ненужных зависимостей порядка выполнения операторов. Рассмотрим, первые два условных оператора в оригинальной процедуре. Есть три пути выполения первого оператора и два пути выполнения второго. Всего шесть путей через оба условных оператора, но осуществимы из них только три: путь через первый условный оператор однозначно определяет путь через второй. 2) Были удалены или локализованы временные переменные. На самом деле, в каждой процедуре переменные присваиваются ровно один раз. Так что вторая реализация в Static Single Assignment форме. Определение порядка выполнения операторов и деструктивные изменения переменных(присваивание) — императивный стиль программирования. Императивные языки одобряют программирование в виде последовательности шагов. И это приводит к программам как оригинальный DeleteNode. Каждый шаг может быть ясным и корректным, но результат может оказаться очень сложным, с большим количеством неосуществимых путей. Эти неосуществимые пути делают код сложнее для понимания, потому что программисту приходится разбираться, какие сценарии поведения возможны, а какие нет. Кроме того, неосуществимые пути могут являться причиной неэффективности кода из-за кореллирующих условных операторов. Неосуществимые пути в программах, главным образом, возникают из-за ненужных зависимостей в порядке выполнения операторов и деструктивного изменения состояния(переприсваивания). Последовательности условных операторов приводят к экспоненциальному росту количества путей. Операция присваивания может порождать зависимости между условными операторами сильно разнесенными в коде друг от друга. Вывод. Было аргументировано, что неосуществимые пути приводят к сложному для понимания коду. А возникают они из-за ненужных использований: последовательностей условных переходов, промежуточных переменных и оператора присваивания. Удаление неосуществимых путей делает программу более функциональной и понятной. |