База по языкам программирования: Как появлялись языки и зачем

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

    Курс этот предназначен прежде всего для junior developer'ов и позволяет повысить уровень аргументации в холиварах на тему «почему PHP (Java, Perl, Bash) отстой».

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

    Часть первая: Как появлялись языки и зачем
    Часть вторая: Принцип сохранения функционала
    Часть третья: Синтаксический сахар или история развития языков


    Как появлялись языки и зачем



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

    Язык программирования — это язык, которым мы задаём правила преобразования информации в удобной для себя или для компьютера форме и ничего более. Фактически, все языки программирования можно свести к операция на машине Тьюринга.

    Машина Тьюринга

    Машина Тьюринга — это бесконечная магнитная лента (вспомните года, когда работал Тьюринг — магнитная лента тогда была очень прогрессивным устройством). Лента разбита на логические ячейки — последовательные отрезки ленты, на которые можно записать тот или иной сигнал (к примеру — ASCII символы).

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

    Программа на машине Тьюринга задаётся в виде таблицы переходов: если символ А — то сдвиг влево, если Б — сдвиг вправо, если С — записать в ячейку D и сдвинуться влево, если E — то остановить работу (и так далее, пока символы не кончатся).

    Одно из главных определений, задаваемых машиной Тьюринга — это контекст исполнения:
    Контекст выполнения программы — совокупность всех данных, определяющих её поведение.

    Парадигмы задания правил


    Как видно по примеру машины Тьюринга, ЯП манипулируют не данными, а преобразованиями данных. Но правила для обработки как-то надо представлять и определять. На данный момент найдено два способа задания правил для обработки — это императивная и декларативная формы записи правил.

    Декларативная форма

    Первая форма называется декларативной. Хороший пример этого типа описания преобразований является алгебраическая запись: a принадлежит отрезку [b,c] (постулируем этот факт), d принадлежит прямой (a,b), если выполняется условие d=f(a,b) (тоже постулируем этот факт).

    Хорошо известными вам декларативными ЯП являются правила описания страницы HTML и CSS. В последнем, к примеру, может постулироваться, что если элемент входит в тот или иной класс, то необходимо покрасить его в красненький.

    Декларативный ЯП описывает не шаги, которые нужно сделать, чтобы получить результат, а то, что требуется получить в качестве результата.

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

    Императивная форма

    Вторая форма представления правил называется императивной. Теоретической моделью для императивного программирования послужила машина Тьюринга.

    Императивная форма: это список приказов, выражаемых в повелительном наклонении. К примеру, присвоить a значение (c-b)/2. Или если a равно b, то перейти к выполнению следующих команд иначе — других команд. Внимание в императивной форме отдаётся не самим данным, а процессу обработки этих данных.

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

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

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

    Парадигмы обработки информации

    Кроме способа задания правил ЯП так же различаются по своему способу подхода к обрабатываемым данным. Если внимательно посмотреть на информацию, которую преобразуют ЯП, то можно увидеть, что она бывает двух типов: дискретная и непрерывная.

    Дискретно-событийная модель

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

    Нетрудно заметить, что при дискретном представлении информации цикличность работы программы задаётся самим способом ввода: прочитали байт — сделали обработку — выплюнули результат.
    Но что происходит, если кусочки информации не выравнены по своим размерам? К примеру, на вход программы подаётся длинный текст, а программа должна оперировать не буквами-символами, а словами?
    Для решения подобных задач вводится понятие события. Событие возникает в ответ на какую-либо распознанную последовательность, прочитанную из источника данных.

    Если рассматривать пример с текстом и словами, то мы байт за байтом читаем данные и записываем в пополняемый буфер памяти. И делаем это до тех пор, пока в потоке данных мы не читаем пробел или точку, что будет означать возникновение события “конец слова”.

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

    В дискретно-событийном подходе обработки информации функционирование системы представляется как хронологическая последовательность событий. Событие происходит в определенный момент времени и изменяет состояние системы.

    Наступление события означает для программы одно очень важное действие: программа меняет своё собственное состояние (контекст выполнения). После наступления события программа может работать исходя из этого знания, что это событие произошло. К примеру, если мы нашли слово “абырвалг”, то теперь можем пользоваться знанием, что оно существует далее, при выполнении хода работ.

    Модель непрерывных данных

    Подход к программированию — “события случаются и мы должны реагировать на это” повсеместно распространён и кажется сейчас чем-то естественным, но это совсем не так. Многие вещи более естественно описывать в непрерывных данных.

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

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

    Оперируя непрерывными данными мы лишаемся понятия события.

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

    Комментарии 25

      +4
      повысить уровень аргументации в холиварах на тему «почему PHP (Java, Perl, Bash) отстой»


      Вот это круто :)
        0
        Кстати, а для чего нужно знать, что ХХХ отстой?
          +6
          для холиваров?
            +1
            А, точно, что-то сразу не сообразил :)
        0
        Чтобы понять, что PHP — отстой, оказывается нужно понимать принципы работы машины Тьюринга. Неожиданно!
          +2
          А вы как думали, холивары — это тоже тяжкий труд, требующий глубокой теоретической подготовки!
          +5
          > Хорошо известными вам декларативными ЯП являются правила описания страницы HTML и CSS.
          Всё ясно.
            +1
            Про Машину Тьюринга: а как же состояния? В каждый момент времени МТ может находиться в одном состоянии из заранее определенного множества состояний. Соответственно, правила перехода зависят не только от символа в текущей ячейке, но и от текущего состояния.

            И терминологическая придирка: все-таки МТ — это не «лента», а «абстрактный исполнитель», лента — это о том, как она устроена.
              0
              хм… Вроде бы это и написал — что машина Тьюринга задаёт понятие контекста исполнения программы.
              0
              HTML — язык разметки. По сути программирования никакого нету.
                0
                Разве HTML не задаёт правила преобразования данных? На вход подаются чистые данные, на выходе мы имеем данные в определённой структуре.
                  0
                  Ну так можно сказать вообще про все языки подряд. Данные преобразовываются в данные. Вы сами об этом писали. Просто все эти понятия — они абстрактные. В реальности мы имеем языки с кучей примесей с других. Смесь многих подходов и парадигм (иногда даже противоречивых).
                    0
                    Естественно! Я же не забыл дописать, что само задание правил преобразования (программа) — по сути — это декларация.

                    На самом деле, понимать, что HTML и другие конфиги — это программы на декларативном языке важно, чтобы не начинать программировать на конфигах.
                  0
                  HTML — ДЕКЛАРАТИВНЫЙ язык программирования для интерпретатора в виде движка браузера. :) Или, можно сократить и сказать, что HTML — «язык разметки». По-сути, это одно и то же.

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

                  ru.wikipedia.org/wiki/%D0%94%D0%B5%D0%BA%D0%BB%D0%B0%D1%80%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5
                  0
                  Наверное везде учат, что HTML — это не язык программирования, но с точки зрения «теории парадигм программирования» HTML — это язык программирования; причем эта теория чуть ли не все способы обработки, хранения и представления информации подводит под ту или иную парадигму.

                  Чего стоит, например, «таблично-ориентированная парадигма». Видимо следует понимать, что при создании электронной таблицы используется так называемый таблично-ориентированный язык.
                  Можно попробовать продолжить эту мысль и придумать текстово-ориентированный язык для создания текстовых документов (правила набора символов для составления текстов на том или ином языке). Хотя это похоже на декларативный язык.

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

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

                    Это не абсурдно, это чертовски красиво. И очень, замечу, полезно: вспомните лисп.
                      0
                      >>Это не абсурдно, это чертовски красиво.

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

                      Тут скрыта более глубокая философия: данные являются неотъемлемой частью любой программы; любая программа сама по себе является данными; любые данные сами являются программой, так как одним своим существованием изменяют окружающую среду (другие данные).

                      Те, кто с высоты своей гордыни говорят, что С++, Java и PHP — это языки программирования, а HTML, CSS, язык Bash (или интерпретатора windows) — это какие-то данные, которые нужно подать настоящим программам для обработки, такие люди мне напоминают физиков позапрошлого века, которые с пеной доказывали, что атом неделимая частица мельче которой ничего не существует.
                        0
                        ОК, мы поняли.
                        Однако такая философия «ломает» устоявшееся представление о том, что такое программа.

                        Пусть есть классическая программа X. Она будет выступать в роли данных для другой программы (компилятора или интерпретатора). Ее компилятор (исполняемый файл) в свою очередь данные для процессора. Процессор — это как бы тоже программа (у него есть команды, логика работы). Однако при всем этом программу X, ее компилятор, процессор будет отличать то, что они могут принимать на вход различные данные. Да, в определенной форме, но все-таки различные. Конечно, можно написать программу замкнутую саму на себе (никакие данные из вне не принимающую). Но возможность этого не делать заложена в самих языках программирования.

                        С другой стороны, утверждается, что документ xxx.html на чистом HTML — это тоже программа. Он является данными для интерпретатора, встроенного в браузер, интерпретатор сам данные для… Однако сам статичный xxx.html, открытый в браузере, не может получать данные и обрабатывать их. Этой возможности нет в самом языке. Поэтому для того, чтобы обрабатывать поступающую информацию, приходится использовать другие языки.

                        Т.е. все равно приходим к тому, что программа, написанная скажем на Python, имеет кардинальное отличие от программы, написанной на HTML, по признаку возможности получать внешние данные.
                          0
                          У вас происходит подмена понятий «программы» и «исполнителя».

                          Упомянутая Вами программа на языке Python — это всего лишь текстовая инструкция для интерпретатора CPyton. Сам по себе листинг ничего делать не умеет. Точно так же как листинг из файла index.html является инструкцией браузеру по прорисовке чего-то на экране.

                          Процессор с философской точки зрения конечно тоже является программой, но отнюдь не потому, что «у него есть команды, логика работы». Система команд и порядок выполнения — это свойства исполнителя команд.
                            0
                            Программа и ее исполнитель зависят друг от друга. Программу на определенном ЯП могут выполнять только специально под этот ЯП созданные исполнители.
                            Иначе можно прийти к выводу, что для любого языка программирования могут существовать совершенно различные исполнители: результат выполнения одного и того же листинга будет зависеть от исполнителя. Но тогда получатся разные языки программирования, хоть и с идентичными ключевыми словами.
                            Таким образом для HTML можно написать интерпретатор, который будет по иному «понимать» теги. Но это будет уже другой язык.

                            Поэтому говорить, что возможность что-то делать заложена в ЯП, а не в его исполнителе, считаю вполне верно.
                              0
                              Вы спорите не о чем. И снова пытаетесь зачем-то подменять понятия.

                              >>Программа и ее исполнитель зависят друг от друга.

                              Все в мире взаимосвязано.

                              >>Программу на определенном ЯП могут выполнять только специально под этот ЯП созданные исполнители.

                              КО?

                              >>Иначе можно прийти к выводу, что для любого языка программирования могут существовать совершенно различные исполнители: результат выполнения одного и того же листинга будет зависеть от исполнителя.

                              Возьмем упомянутый вами Python — для него реализовано 10 интерпретаторов/исполнителей ru.wikipedia.org/wiki/Python#.D0.A0.D0.B5.D0.B0.D0.BB.D0.B8.D0.B7.D0.B0.D1.86.D0.B8.D0.B8
                              Тогда по вашей логике существует 10 версий Python. Бедные разработчики — они ведь и не догадываются, что программируя на одной конкретной версий Python они пишут одновременно на 10 языках программирования. :)

                              >>Поэтому говорить, что возможность что-то делать заложена в ЯП, а не в его исполнителе

                              Это полный абсурд. Возможность «деланья» — это свойство исполнителя. Программа — это перечень инструкций для конкретного «деланья». Язык программирования — это правило составления таких инструкций.

                              Или вы хотите продолжить спорить и доказывать, что «ходить строевым шагом» — это возможность русского языка, так как на русском языке написан устав, который обязаны выполнять все военные????
                                0
                                Уточню.
                                Все исполнители Python выдадут примерно одинаковый смысловой результат, выполнив один и тот же листинг. Вы же выше писали, что результат зависит от исполнителя. Можно сказать утверждали, что для ЯП может существовать два исполнителя, работа которых даст совершенно разный смысловой результат выполнения одного и того же листинга.
                                Это и имелось ввиду здесь:
                                Иначе можно прийти к выводу, что для любого языка программирования могут существовать совершенно различные исполнители: результат выполнения одного и того же листинга будет зависеть от исполнителя.

                                Смысл, назначение, работа программы не меняются от того, чем ее выполнили. А если меняются, значит исполнители интерпретируют разные языки. КО
                                  0
                                  >>Вы же выше писали, что результат зависит от исполнителя. Можно сказать утверждали, что для ЯП может существовать два исполнителя, работа которых даст совершенно разный смысловой результат выполнения одного и того же листинга.

                                  1) Я такого не писал. Это писали Вы.
                                  2) В этих Ваших словах есть смысл. Язык PHP он один и тот же, но если попробовать выполнить написанную на нем программу в PHP3 и PHP4, то получим разный результат (это касается всех языков программирования — компиляторы/интерпретаторы могут поставляться различными разработчиками, а так же в следствии эволюции имеют различные версии).

                                  >>Смысл, назначение, работа программы не меняются от того, чем ее выполнили. А если меняются, значит исполнители интерпретируют разные языки.

                                  Смысл и назначение не изменятся. А работа зависит от (если мы говорим о компьютерных языках программирования) железа, операционной системы и её политик безопасности, архитектуры процессора, доступности ресурсов, состояния переменных окружения, версий компиляторов/интерпретаторов.

                                  По прежнему не пойму о чем Вы пытаетесь спорить с использованием софизмов и подменой предметов. Дальнейшее обсуждение этого вопроса считаю неуместным. Если Вам хочется верить, что голый текст сохраненный в компьютерном файле — это и есть язык программирования и что он сам по себе умеет на компьютере что-то делать, то не смею далее запрещать Вам заблуждаться.
                                    0
                                    Вам хочется верить, голый текст сохраненный в компьютерном файле — это и есть язык программирования и что он сам по себе умеет на компьютере что-то делать

                                    Нет. ЯП — формальная знаковая система, предназначенная для записи компьютерных программ (Википедия).
                                    Речь шла о том, всякий ли файл следует считать программой.
                                      0
                                      Оттуда же: Компью́терная програ́мма — последовательность инструкций, предназначенная для исполнения устройством управления вычислительной машины.

                                      Если данные в файле предназначены для исполнения, являются инструкциями, то этот файл программа. В этом отношении HTML-файл (или любой аналогичный по назначению язык разметки) является программой, содержащей инструкции как интерпретировать те или иные данные, записанные с помощью формальной знаковой системы.

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое