Михаил @mikhanoid
ИММ УрО РАН
Information
- Rating
- Does not participate
- Registered
- Activity
Specialization
System Software Engineer, scientific programming
Scheme
C
Assembler
Linux
Maths
Julia
Compilers
Math modeling
Machine learning
Computer Science
ИММ УрО РАН
Компьютер (MT c вводом\выводом) же может с такой последовательностью производить осмысленные операции, например, считать текущее математическое ожидание. А другая машина может этим пользоваться для своей активности, и так далее.
Классическая же МТ даже не сможет начать работать с этим входным потоком, ведь его изначально надо будет разместить на ленте.
По делу. Рекурсия действительно не обязательна - последний вариант это показывает. Но в ФП и ООП рекурсивное решение кажется более естественным, в этом основная мысль. Потому что эти подходы как раз предполагают не синтез решения, а декомпозицию задачи, при этом сразу же. Я же утверждаю, что объекты при проектировании должны не навязываться сверху при проектировании, а возникать при реализации программы, проект которой заключается в описании необходимых преобразований над некими состояними (не автоматными), если в ходе проектирования и программирования этих преобразований будет видно, что возникают некие структуры из данных и алгоритмов, то это прямое указание на модульную декомпозицию, или на классовую, кому как удобнее. Но это следствие того, как происходят преобразования в программе, а не их причина. Не нужно, по моему глубокому убеждению, начинать проектирование с определения модулей и классов. Сами потом появятся.
Эмс... И про автоматы. Те состояния и их изменения, о которых я говорю, это не автоматные состояния и не автоматные изменения. Автомат - это опять же логическая конструкция с постоянными свойствами, которая должна возникать в процессе решения, а не навязываться сверху путём декомпозиции программы на множество этих самых автоматов. Потому что состояния у процессов могут быть потенциально бесконечными, а конечные автоматы с такими объектами оперировать не в состоянии. Нужны как минимум МП-автоматы, но это не панацея. Панацея - это сдвоенные МП-автоматы, которые тъюринг-полные. Которые, кстати, невозможны в рамках подхода иерархических конечных автоматов, которые предлагают авторы указанного Вами сайта.
Но даже если бы были - это же жутко неудобно. Попробуйте в этих автоматах выразить алгоритм пирамидальной сортировки. Конечно, во многих случаях динамика в программе описывается именно конечными автоматами, они очень полезный инструмент. Но во многих случаях они ничем не могут помочь, в преобразованиях данных возникают совсем иные структуры.
И на все три пункта. Цель не в том, чтобы сравнить языки по мощности, а в том, чтобы показать, как подходы к проектированию влияют на конечный результат. Там прямо в тексте написано, что линейный вариант с переименованием списков можно реализовать и на Haskell в виде функций над монадами (хоть это и потребует шаманства некоторого), и в виде объектов, но это не первая мысль, которая приходит в голову при построении программ в рамках функциональной и ОО парадигм. Первое, что приходит в голову - это разложение на очевидные объекты, которые мы берём из своего материального или математического представления о программе. Но на деле 'существующим' в процессе вычисления может быть нечто иное.
Без определения N можно просто запустить бесконечный цикл. На каждом шаге, конечно, списки будут конечными, но само вычисление может продолжаться бесконечно долго, конечно, оно будет не менее ресурсоёмким, чем рекурсия - понадобиться постепенное наращивание памяти и так далее. НО хоть какие-то результаты можно будет получать уже во время вычислений, а рекурсия будет просто молча бесконечно долго спускаться к решению.
Inferno и Plan9 далеко ушли в другом: в эффективной и в простой для использования распределённости и в очень простом для программиста и пользователя API. Это действительно уникально и даёт много интересных возможностей.
Совсем не важно, на каком языке система написана, важно, что она позволяет делать.
Оба подхода заставляют по форме (что должно быть) определить содержание (как должно быть). Вобщем-то вполне себе математичный подход. Теоретически красивый. Да, мы вот сейчас всё пишем и пишем, и на словах, действительно ООП гораздо красивее обычного структурного подхода. Кроме того, можно кучу книжек писать, ООП - богатая среда для мудрствований, например, вот те же замечательные философствования о шаблонах и рефакторинге. Так же как и функциональное программирование, а когда оно ещё и с монадами, то вообще, ууУУух как поумничать можно и статьи пописать.
C же освобождает от необходимости проектировать строго определённый интерфейс, конечно, от ответа на вопрос: что код должен делать? уйти вряд ли удасться, но ответ этот может быть достаточно нестрогим. Язык ориентирован на работу с данными, а не объектами. Если я совершу ошибку на этапе придумывания интерфейса, то мне никто не мешает напрямую залезть в структуру данных, и написать новый код для работы с ней, в том месте, где он нужен. Да, это грязно, это не математично, это нарушение кучи принципов, об этом не напишешь умную книжку, потому что это глупо, но это работет. И работает не только корректно, но и эффективно. Если подобный код мне нужен будет во многих местах - родилась абстракция - я его вынесу в соответсвующий модуль, и доступ к нему сделаю частью интерфейса.
Мог бы я подобное обнаружить на бумажке? Запросто, если бы писал на бумажке настоящую программу, до уровня операторов и вызов функций, а не просто рисовал бы стрелочки, то наверняка обнаружил бы то же самое. Но на бумажке невозможно написать нечто более или менее сложное.
Я могу предполагать, что в этом случае списки эффективны, но на реальных данных может оказаться, что они убивают производительность, или, вдруг оказывается, что для реализации некоторой возможности в новой версии нужно обращение к произвольному элементу. Если я это всё буду учитывать только после того, как напишу программу на бумажке, потом закодирую на ООП, потом откомпилирую, потом пойму, что все мои расчёты, мягко говоря, некорректные, потом опять сяду за бумажку... Я рискую ни одной эффективной программы за всю жизнь не написать.
В итоге, конечно, у меня тоже появляются объекты в программе, но границы у них не жёсткие, а размытые, и объекты именно появляются, а не спускаются сверху. Не тотальная закапсулированность позволяет упростить взаимодействие, особенно, при использовании в новом коде. А то, что объект возник естественным путём освобождает меня от необходимости прописывать какую-то невостребованную функциональность.
Да, всё то же самое можно делать и на C++, например. Но тогда надо будет делать все данные и методы изначально открытыми, и возникает вопрос, а зачем тогда этот весь этот лишний классовый синтаксис?
Ещё можно сказать, что в Smalltalk именно так формировались интерфейсы. Они формировались снизу вверх. Они возникали, а не навязывались сверху. Наследования же вообще не было. Все эти, на мой взгляд, сложности, связанные с проектирование сверху вниз, появились в компилируемых языках, в которых для повышения эффективности стали путать типы и объекты.
И последнее замечание: в книжках по функциональному программированию, обычно, всё истолковывается в терминах и примерах из императивных языков программирования, поэтому, в них со сравнением с другими технологиями всё лучше.
И я должен буду выполнять много сложной работы по переписыванию кода, настолько сложной, что для этого появляются автоматизированные средства.