Ссылки для упрощенного доступа

logo-print

Языки программирования и живые языки: сходства и различия


На вопросы Александра Костинского отвечают Владимир Губайловский и Александр Сергеев

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

Об этом мы будем сегодня говорить с профессиональными программистами Владимиром Губайловским и Александром Сергеевым.

Мой первый вопрос Владимиру Губайловскому.

Чем отличаются языки программирования, как языки общения человека с машиной, от живых языков. От того языка, на котором каждый из нас говорит?

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

Александр Костинский: Давайте расскажем, чем они похожи. Воспользуемся такими основными понятиями, как синтаксис и семантика.

Владимир Губайловский: Синтаксис это - правила построения правильных высказываний внутри языка. Когда у вас есть определенный набор лексем (неважно каких - лексем русского языка или лексем языка Паскаль), то у вас есть правила, как из правильных слов собрать правильное предложение. Вот именно этим и занимается синтаксис. Семантика, естественно, занимается не этим. Семантика занимается смыслом. Семантика говорит, если у нас есть лексема или правильно построенное предложение, то оно значит то-то. Обычно лексеме приписывается пара - означаемое и денотат, иногда только означаемое. Слово денотат поясню на примере. Когда я говорю стол, то денотатом будет вот этот конкретный стол, а общее понятие языка "стол" будет означаемым.

Александр Костинский: Грубо говоря, в теории формальные языки, языки программирования, очень похожи на теории языков, которые создавали лингвисты, например, Фердинанд де Соссюр?

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

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

Александр Костинский: Мечта двоечника.

Владимир Губайловский: В общем, да, да. Мечта двоечника. У меня был знакомый эсперантист, который по-русски не умел писать стихи, а на эсперанто у него получалось просто блистательно, потому что там все слова рифмуются друг с другом.

Александр Костинский: Конечно, все существительные оканчиваются на "о".

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

Александр Костинский: Но из-за этого сумасшедшая гибкость.

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

Александр Сергеев: Причем выполняющих то же самое действие, которое предписано на Паскале, вот в чем разница. Легко превратить в набор нулей и единичек любую фразу. Очень важный момент, откуда берется семантика в языках программирования. Это полумистическая вещь. Строго формальной семантики нет, конечно же, потому что ее никак не описать. Мы не можем внутри языка дать реальную ссылку на денотат. Мы не можем реально описать то действие, которое должны осуществить, мы не можем его втащить в описание языка, потому что действие это процесс во времени в реальной машине, а в языке в любом описании, в любой инструкции, в любой книжке по языку только слова и объяснения. Самое интересное, чем обеспечивается семантика в программировании. Когда мы берем язык программирования Паскаль и пишем на нем какую-то инструкцию, запускаем транслятор, транслятор превращает ее в машинный код, машинный код записывается в память компьютера. А вот дальше начинает работать процессор - электронный полупроводниковый кристалл, который из памяти вытаскивает числа (машинные коды) и в соответствии с ними работает. Что значит работает в соответствии с ними? Эти самые коды хранятся в памяти в виде электрических зарядов (1 - есть заряд, 0 - нет заряда), то есть в виде физических состояний. И процессор, как физическая электронная система по законам физики, управляется вот этими самыми зарядами - действует как нормальная физическая система, следуя физическим законам. Но эти физические законы приводят к тому, что если в этом месте записан код, соответствующий коду операций сложения, то в результате в двух других ячейках будут взяты числа, сложены и помещены в третью ячейку. Вот такой процесс будет произведен в кристалле. В конце концов данные, которые нам нужны, будут выведены из машины и получены. Вот этот момент труден для восприятия. Мы вроде бы писали слова и символы на Паскале, они превратились в машинный код, но машинный код это числа. Числа это тоже в некотором смысле слова, хотя состоящие из цифр. И вдруг эти числа стали действием в физическом кристалле - слово превратилось в дело - возникло некое действие, строго соответствующее смыслу слова и собственно этим действием слово и осмыслено.

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

Александр Сергеев: Да, но кто выполнял инструкцию первоначально? Ее исполнял человек. Он понимал инструкцию, читая по бумажке и выполнял.

Александр Костинский: А потом инструкция исполнялась ткацким станком Жаккара, считывая программу с перфокарт.

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

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

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

Александр Костинский: Полу?

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

Александр Костинский: И пропущены 15 страниц математического текста.

Владимир Губайловский: "Легко видеть", и эти 15 страниц как раз опускаются в тексте.

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

Александр Костинский: Мы можем сказать, если говорить о языке математики, которая тоже полуформальный язык, что по сравнению с ней язык программирования гораздо более жестко формализованный язык, потому что тут на фразе "легко показать" машина остановится и будет просто сбой.

Владимир Губайловский: И слава Богу.

Александр Сергеев: Хорошо, если сбой, а если просто неправильное функционирование?

Владимир Губайловский: Я, кстати, могу рассказать еще одну историю. Одна из самых громких ошибок произошла, когда французская ракета "Ариан" упала стартуя с космодрома в Гвиане, причем ошибка была следующего типа. Ошибка была в модуле, который всегда работал в этой ракете и работал прекрасно, но в этом случае ракета была нового типа и у нее был при взлете другой угол наклона. И когда программа начала рассчитывать траекторию с этим другим углом наклона, то оказалось, что в этом интервале данных она дает сбой, хотя модуль был просто скопирован из одной ракеты в другую. И она упала.

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

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

Александр Костинский: Абстрактный исполнитель в данном случае процессор?

Александр Сергеев: Или воображаемый процессор.

Владимир Губайловский: Для Паскаля это будет транслятор.

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

Александр Костинский: Миллион раз в секунду попросили и она миллион раз делает то, что нужно.

Владимир Губайловский: А вообще-то, это произошло в тот момент, когда Клод Шеннон понял, что электрические схемы работают так же, как алгебра логики. Сложение чисел и операторы "и", "или", "не", в общем, легко реализуются в электрических схемах. Это было просто сумасшедшим прорывом.

Александр Костинский: Что делали Лейбниц и Буль? Они пытались таким образом формализовать человеческие рассуждения, чтобы они были однозначно определяемыми. Мечта Лейбница: мы не должны бесполезно спорить, наши рассуждения должны быть подобны вычислениям и результат должен быть объективен. И компьютер реализовал эту мечту, к сожалению, ограниченно. Оказалось, что только небольшой ряд умозаключений, которые относятся к математике и точным наукам, мы можем таким строгим образом провести.

Владимир Губайловский: А вот какой именно этот ряд как раз и описал Алан Тьюринг, который очень формально и строго дал определение того, что вообще компьютер может посчитать и это тоже произошло в 30-е годы XX-го века. То есть, как это ни странно, наверное, прозвучит, с тех пор мы в нашем программировании ничего серьезного дальше и не достигли. Мы спокойно, вдумчиво реализуем идеи Шеннона и Тьюринга.

Александр Сергеев: На самом деле мне бы хотелось одним взглядом окинуть эволюцию языков программирования, где разные люди насчитывают разное количество этапов, обычно не меньше четырех. Я для себя вижу примерно семь основных этапов. Первый этап - это уровень программирования, когда мы фактически вставляли в компьютер деталь с программой. Второй уровень, это когда мы программу отделили от механических деталей и стали ее вводить в машину в двоичном коде в память компьютера. Третий уровень, когда появились языки типа Ассемблера, по-прежнему работающие команда в команду, но они оторвались от физических ячеек, от машинного кода. Четвертый уровень, когда мы перешли к языкам высокого уровня типа ФОРТРАНа, Паскаля, С, где мы стали записывать алгоритмы выражениями на языке более ли менее близком к человеческому, то есть, вычисления записывать в виде формул в записи близкой к математической. Условные переходы так и записывали словами: "если", следует условие, "то" нужно сделать это; циклы: пока выполняется условие, то повторять раз за разом то-то и то-то. Языки высокого уровня - четвертый уровень. Пятый уровень это появление структурно-модульных языков. Шестой - появление объектных языков. И седьмой уровень, тот, на который сейчас только-только пытаются выходить это уровень кейс-систем, систем проектирования текстографических программ. (CASE - Computer Aided Software Engineering). Расшифровывается - разработка программного обеспечения с компьютерной автоматизированной поддержкой. Там мы даже отрываемся кое-где от языка, переходим на язык графики. Каждый из этих уровней был не случайным и появился в свое время. Например, создать язык высокого уровня в момент, когда программировали только в машинных кодах, было практически невозможно. Например, сложность написания транслятора с языка высокого уровня такова (это ведь тоже программа, которая переводит, например, с языка Паскаль в язык машинных кодов), что ее не под силу написать человеку в машинных кодах. Или практически не под силу - слишком трудно. Поэтому прежде, чем написать транслятор с языка Паскаль, нужно было создать язык Ассемблер, чтобы на нем писать транслятор с языка Паскаль. Пока не было языков высокого уровня, то невозможно было разрабатывать языки кейс-систем (объектные языки может быть и можно было). Языки кейс-систем просто невозможно разрабатывать, пока полностью не утряслась вся теория трансляции языков высокого уровня. На все эти достижения новых уровней уходили десятилетия, и перескочить через уровни невозможно. На самом деле в программировании мы столкнулись с такой поразительной вещью. Раньше это можно было видеть в некоторых технических областях, но в программировании это особенно ясно видно. Сложность системы, как категория это если не измеримая, то ощутимая вещь и стоя на определенном уровне сложности можно с помощью долгих и упорных трудов забраться на один уровень выше, но невозможно никакими силами перескочить сразу на два уровня. Поэтому все задачи, которые в программировании опережали свое время, кончались неудачей. Только в тех случаях добивались успеха, когда удавалось увидеть ту одну ступеньку, как в головоломке, тот единственный шаг, который доведет нас до полного решения. Удавалось увидеть этот уровень, на который предстояло забраться, вот тогда и получался новый этап развития компьютерной техники. Потом на этот уровень выходили все, осваивали его, начинали чувствовать его ограниченность и тогда создавали языки или системы программирования нового уровня, которые позволяли вскочить на следующую ступеньку. И надо сказать, что не умеют заглядывать даже на один-два уровня вперед. Кейс-системы сейчас видны, а что будет дальше? Только туманные разговоры про искусственный интеллект, которые ведутся уже тридцать-сорок лет и имеют кое-какие воплощения, но очень скромные и ограниченные.

Александр Костинский: В передаче участвовали профессиональные программисты Владимир Губайловский и Александр Сергеев.

Все ссылки в тексте программ ведут на страницы лиц и организаций, не связанных с радио "Свобода"; редакция не несет ответственности за содержание этих страниц.

XS
SM
MD
LG