База На Языках Программирования: Как Появились Языки И Почему

Всем привет. Публикую отрывки из вводного курса нашего компании в промышленном программировании.

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

Этот курс предназначен в первую очередь для младших разработчиков и позволяет повысить уровень аргументации в холиварах на тему «почему PHP (Java, Perl, Bash) — отстой».

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

Также ясно и ясно объясняется, что такое ООП и функциональное программирование.

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



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

Язык необходим для обработки данных и представления результата обработки в той или иной форме.

Компьютер всегда имеет источник данных и приемник данных.

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

Язык программирования — это язык, с помощью которого мы задаем правила преобразования информации в удобную для себя или компьютера форму и не более того.

Фактически все языки программирования можно свести к операциям машины Тьюринга.



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

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

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

верно.

После выполнения этих двух действий цикл повторяется; никакие данные не передаются между циклами.

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

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

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



Парадигмы установления правил

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

Но правила обработки как-то нужно представить и определить.

На данный момент найдено два способа задания правил обработки — это императивная и декларативная формы написания правил.



Декларативная форма
Первая форма называется декларативная.

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

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

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

Меньше внимания уделяется процессу преобразования данных.



Повелительная форма
Вторая форма изложения правил называется императивной.

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

Повелительная форма: Это список приказов, выраженных в повелительном наклонении.

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

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

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

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



Парадигмы обработки информации
Помимо способа задания правил, ПЛ различаются и подходом к обрабатываемым данным.

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

Дискретная модель событий Классическим примером дискретного представления информации является та же машина Тьюринга.

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

Другим примером дискретного представления является обработка входящего потока цифровых аудиоданных.

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

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

Событие возникает в ответ на некоторую распознанную последовательность, считанную из источника данных.

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

И делаем это до тех пор, пока не прочитаем в потоке данных пробел или точку, что будет означать возникновение события «конец слова».

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

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

Событие происходит в определенный момент времени и меняет состояние системы.

Возникновение события означает для программы одно очень важное действие: программа меняет собственное состояние (контекст выполнения).

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

Например, если мы нашли слово «абырвалг», то теперь мы можем использовать знание о его существовании дальше, при проведении хода работы.

Непрерывная модель данных Подход к программированию — «события случаются, и мы должны на них реагировать» широко распространен и кажется сейчас чем-то естественным, но это совсем не так.

Многие вещи более естественно описывать в виде непрерывных данных.

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

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

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

Круг в данном случае представляется как массив пикселей.

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

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

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

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

Там, где нам нужна картина «общей картины», наиболее удобен подход аналитических языков: получение срезов данных, описание структур данных, решение математических функций, описание графики, непрерывные преобразования одного входящего потока в другой.

Теги: #образование #обучение #теория программирования #программирование

Вместе с данным постом часто просматривают: