Современные языки программирования и .NET Двухсеместровый учебный курс
I семестр: основы функционального программирован...
174 downloads
221 Views
5MB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Современные языки программирования и .NET Двухсеместровый учебный курс
I семестр: основы функционального программирования и computer science II семестр: разработка гетерогенных программных систем © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Предлагаем Вашему вниманию курс лекций, посвященный современным языкам программирования. Изучение языков программирования базируется на теоретическом фундаменте современных подходов и математических формализаций, принятых в мировом computer science. В качестве технологической основы и инструментальной платформы для исследования языков программирования предлагается новейшая разработка корпорации Microsoft – уникальный по идеологии и широте поддержки языков программирования комплекс программного обеспечения на основе так называемой методологии .NET. Курс имеет целью введение в теорию и практику разработки программных систем и состоит из двух взаимосвязанных этапов, преподавание которых физически разделено по времени на два семестра. Первый семестр посвящен основам программирования и теоретическому введению в computer science. Второй семестр предполагает (на основе знакомства с азами теории и практики программирования) более профессиональные аспекты реализации гетерогенных программных систем.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Содержание лекции 1. 2. 3. 4. 5. 6.
Предмет и назначение курса Структура курса Классификация языков программирования Преимущества и недостатки основных классов языков программирования Основные подходы к программированию Библиография
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. Прежде всего, необходимо познакомить слушателей с предметом учебного курса и его назначением. Затем речь пойдет о структуре курса и назначении каждого из его этапов. Собственно в лекции слушателям будет предложен вариант классификации языков программирования, рассмотрена история их развития и основные подходы к разработке программных систем, отмечены преимущества и недостатки каждого из языков и подходов. Наконец, для желающих глубже исследовать предмет будут представлены ссылки на важнейшие работы теоретического и практического плана по теме лекции.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Предмет курса: современные языки программирования Назначение курса: фундаментальное введение в современную теорию и практику программирования Цель курса: формирование адекватного мировоззрения на разработку программного обеспечения в современных условиях и «хорошего стиля» программирования Аудитория: студенты технических вузов, специализирующихся на программировании Начальные знания: минимальны (фундаментальные понятия из школьного курса математики: «функция», «множество», … на интуитивном уровне) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как явствует из названия, основным предметом настоящего учебного курса являются языки программирования. Курс предназначен для фундаментального, глубокого ознакомления студентов с основами современных тенденций в теоретическом и практическом программировании. При этом в теоретическом аспекте курс опирается на апробированный фундамент семейства научных дисциплин, известных под названием computer science. К сожалению, большинство из известных в настоящее время курсов либо изобилуют излишними техническими деталями и отвлекают слушателей от глубинной сути программирования, либо представляют собой сухие теоретические дисциплины, достаточно далеко отстоящие от практики программирования. Нашей задачей будет формирование верного понимания основ разработки программного обеспечения в теоретическом и практическом аспектах, а также хорошего тона, вкуса, или, как принято говорить, стиля программирования, исходя из сравнительного анализа наиболее значимых современных подходов. Существенным преимуществом курса является минимум базовых требований для слушателей, преимущественно студентов младших курсов технических вузов, специализирующихся на программировании, от которых требуется владение базовыми понятиями математики, фактически изучаемых еще в курсе средней школы: «функция», «множество» и т.п.
Классификация языков программирования
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перейдем непосредственно к теме первой лекции, которая посвящена истории, эволюции и классификации языков и подходов к программированию.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Ранние языки программирования Время появления: 1940-е г.г. Краткая характеристика: линейная последовательность элементарных инструкций «низкого уровня» Преимущества: • высокая вычислительная эффективность Недостатки: • существенная зависимость от среды вычислений Примеры: • машинные коды, ассемблеры © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Первые языки программирования возникли относительно недавно. Различные исследователи указывают 20-е, 30-е и даже 40-е годы XX столетия. Нашей задачей является не установление самого раннего языка, а поиск закономерностей в их развитии. Как и следовало ожидать, первые языки программирования, как и первые ЭВМ, были довольно примитивны и ориентированы на численные расчеты. Это были и чисто теоретические научные расчеты (прежде всего, математические и физические), и прикладные задачи, в частности, в области военного дела. Программы, написанные на ранних языках программирования, представляли собой линейные последовательности элементарных операций с регистрами, в которых хранились данные. Нужно отметить, что ранние языки программирования были оптимизированы под ту аппаратную архитектуру конкретного компьютера, для которого они предназначались, и хотя они обеспечивали высокую эффективность вычислений, до стандартизации было еще далеко. Программа, которая была вполне работоспособной на одной вычислительной машине, зачастую не могла быть выполнена на другой. Таким образом, ранние языки программирования существенно зависели от того, что принято называть средой вычислений и приблизительно соответствовали современным машинным кодам или языкам ассемблера.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Императивные (процедурные) языки программирования (1) Время появления: 1950-е г.г. Краткая характеристика: программа – последовательность инструкций-операторов, включающих блоки типичных действий – процедуры или функции Преимущества: • более высокий уровень абстракции; • меньшая машинная зависимость; • более широкая совместимость © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Следующее десятилетие ознаменовалось появлением языков программирования так называемого «высокого уровня», по сравнению с ранее рассмотренными нами предшественниками, соответственно именуемыми низкоуровневыми языками. При этом различие состоит в повышении эффективности труда разработчиков за счет абстрагирования или отвлечения от конкретных деталей аппаратного обеспечения. Одна инструкция (оператор) языка высокого уровня соответствовала последовательности из нескольких низкоуровневых инструкций, или команд. Исходя из того, что программа, по сути, представляла собой набор директив, обращенных к компьютеру, такой подход к программированию получил название императивного. Еще одной особенностью языков высокого уровня была возможность повторного использования ранее написанных программных блоков, выполняющих те или иные действия, посредством их идентификации и последующего обращения к ним, например, по имени. Такие блоки получили название функций или процедур, и программирование приобрело более упорядоченный характер.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Императивные (процедурные) языки программирования (2) Преимущества: • содержательная значимость текстов программ; • унификация программного кода; • повышение производительности труда программистов Недостатки: • большие трудозатраты на обучение; • меньшая эффективность программного кода Примеры: Fortran, ALGOL, PL/1, APL, BPL, COBOL, Pascal, C, Basic © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кроме того, с появлением языков высокого уровня зависимость реализации от аппаратного обеспечения существенно уменьшилась. Платой за это стало появление специализированных программ, преобразующих инструкции возникших языков в коды той или иной машины, или трансляторов, а также некоторая потеря в скорости вычислений, которая, впрочем, компенсировалась существенным выигрышем в скорости разработки приложений и унификацией программного кода. Нужно отметить, что операторы и ключевые слова новых языков программирования были более осмысленны, чем безликие цифровые последовательности кодов, что также обеспечивало повышение производительности труда программистов. Естественно, для обучения новым языкам программирования требовались значительные затраты времени и средств, а эффективность реализации на прежних аппаратных возможностях снижалась. Однако трудности эти носили временный характер, и, как показала практика программирования, многие из первых языков высокого уровня оказались настолько удачно реализованными, что активно используются и сегодня. Одним из таких примеров является язык Fortran, реализующий вычислительные алгоритмы. Другой пример - язык APL, трансформировавшийся в BPL и затем в C. Основные конструкции последнего остаются неизменными вот уже несколько десятилетий и присутствуют в языке C#, который нам предстоит изучить. Примеры других языков программирования: ALGOL, COBOL, Pascal, Basic.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Декларативные языки программирования (1) Время появления: 1960-е г.г. Краткая характеристика: программа – описание действий, которые необходимо осуществить Преимущества: • простота верификации и тестирования программ; • строгость математической формализации; • высокая степень абстракции
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В 60-х г.г. возникает новый подход к программированию, который до сих пор успешно конкурирует с императивным, а именно, декларативный подход. Суть подхода состоит в том, что программа представляет собой не набор команд, а описание действий, которые необходимо осуществить. Этот подход, как мы увидим впоследствии, существенно проще и прозрачнее формализуем математическими средствами. Отсюда следует тот факт, что программы проще проверять на наличие ошибок (тестировать), а также на соответствие заданной технической спецификации (верифицировать). Высокая степень абстракции также является преимуществом данного подхода. Фактически, программист оперирует не набором инструкций, а абстрактными понятиями, которые могут быть достаточно обобщенными.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Декларативные языки программирования (2) Недостатки: • сложность эффективной реализации; • необходимость фундаментальных математических знаний Примеры: LISP (Interlisp, Common Lisp, Scheme), SML, Haskell, Prolog
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду На начальном этапе развития декларативным языкам программирования было сложно конкурировать с императивными в силу объективных трудностей при создании эффективной реализации трансляторов. Программы работали медленнее, однако, они могли решать с меньшими трудозатратами более абстрактные задачи. В частности, язык SML, который мы будем изучать в данном курсе, был разработан как средство доказательства теорем. Различные диалекты языка LISP (основные из них представлены на слайде), возникли потому, что ядро и идеология этого языка оказались весьма эффективными при реализации символьной обработки (анализе текстов). Другие характерные примеры декларативных языков программирования приведены на слайде.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Функциональные языки программирования (1) Время появления: 1960-е г.г. Краткая характеристика: программа – функция, аргументы которой, возможно, также являются функциями Преимущества: • полностью автоматическое управление памятью компьютера («сборка мусора»); • простота повторного использования фрагментов кода; • расширенная поддержка функций с параметрическими аргументами (параметрический полиморфизм); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Одним из путей развития декларативного стиля программирования стал функциональный подход, возникший с появлением и развитием языка LISP. Отличительной особенностью данного подхода является то обстоятельство, что любая программа, написанная на таком языке, может интерпретироваться как функция с одним или несколькими аргументами. Такой подход дает возможность прозрачного моделирования текста программ математическими средствами, а, значит, весьма интересен с теоретической точки зрения. Сложные программы при таком подходе строятся посредством агрегирования функций. При этом текст программы представляет собой функцию, некоторые аргументы которой можно также рассматривать как функции. Таким образом, повторное использование кода сводится к вызову ранее описанной функции, структура которой, в отличие от процедуры императивного языка, прозрачна математически. Более того, типы отдельных функций, используемых в функциональных языках, могут быть переменными. Таким образом обеспечивается возможность обработки разнородных данных (например, упорядочение элементов списка по возрастанию для целых чисел, отдельных символов и строк) или полиморфизм. Еще одним важным преимуществом реализации языков функционального программирования является автоматизированное динамическое распределение памяти компьютера для хранения данных. При этом программист избавляется от рутинной обязанности контролировать данные, а при необходимости может запустить функцию «сборки мусора» – очистки памяти от тех данных, которые больше не потребуются программе (обычно этот процесс периодически инициируется компьютером).
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Функциональные языки программирования (2) Преимущества: • абстрагирование от машинного представления данных; • прозрачность реализации самоприменяемых (рекурсивных) функций; • удобство символьной обработки данных (списки, деревья) Недостатки: • нелинейная структура программы; • относительно низкая эффективность Примеры: LISP, SML, CaML, Haskell, Miranda, Hope © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Таким образом, при создании программ на функциональных языках программист сосредотачивается на области исследований (предметной области) и в меньшей степени заботится о рутинных операциях (обеспечении правильного с точки зрения компьютера представления данных, «сборке мусора» и т.д.). Поскольку функция является естественным формализмом для языков функционального программирования, реализация различных аспектов программирования, связанных с функциями, существенно упрощается. В частности, интуитивно прозрачным становится написание рекурсивных функций, т.е. функций, вызывающих самих себя в качестве аргумента. Кроме того, естественной становится и реализация обработки рекурсивных структур данных (например, списков – базовых элементов, скажем, для семейства языков LISP, деревьев и др.) Благодаря реализации механизма сопоставления с образцом, такие языки как ML и Haskell весьма хорошо применимы для символьной обработки. Естественно, языки функционального программирования не лишены недостатков. Часто к ним относят нелинейную структуру программы и относительно невысокую эффективность реализации. Однако, первый недостаток достаточно субъективен, а второй успешно преодолен современными реализациями, в частности, рядом последних трансляторов языка SML, включая и компилятор для среды Microsoft .NET. Характерные примеры декларативных языков программирования приведены на слайде.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Логические языки программирования (1) Время появления: 1970-е г.г. Краткая характеристика: программа – совокупность правил или логических высказываний с причиной и следствием Преимущества: • высокий уровень абстракции; • удобство программирования логики поведения; • удобство применения для экспертных систем; • механизм откатов (backtrack) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В 70-х г.г. возникла еще одна ветвь языков декларативного программирования, связанная с проектами в области искусственного интеллекта, а именно, языки логического программирования. Согласно логическому подходу к программированию, программа представляет собой совокупность правил или логических высказываний. Кроме того, в программе допустимы логические причинно-следственные связи, в частности, на основе операции импликации. Таким образом, языки логического программирования базируются на классической логике и применимы для систем логического вывода, в частности, для так называемых экспертных систем. На языках логического программирования естественно формализуется логика поведения, и они применимы для описаний правил принятия решений, например, в системах, ориентированных на поддержку бизнеса. Важным преимуществом подхода является достаточно высокий уровень машинной независимости, а также возможность откатов – возвращения к предыдущей подцели при отрицательном результате анализа одного из вариантов в процессе поиска решения (скажем, очередного хода при игре в шахматы), что избавляет от необходимости поиска решения полным перебором вариантов и увеличивает эффективность реализации.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Логические языки программирования (2) Недостатки: • ограниченный круг задач; • нелинейная структура программы; • недостаточно эффективная реализация Примеры: Prolog, Mercury
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Одним из недостатков логического подхода в концептуальном плане является специфичность класса решаемых задач. Другой недостаток практического характера состоит в сложности эффективной реализации для принятия решений в реальном времени, скажем, для систем жизнеобеспечения. Нелинейность структуры программы является общей особенностью декларативного подхода и, строго говоря, является оригинальной характеристикой, а не объективным недостатком. В качестве примеров языков логического программирования можно привести Prolog (название возникло от слов PROgramming in LOGic) и Mercury.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Объектно-ориентированные языки программирования (1) Время появления: 1970-е г.г. Краткая характеристика: программа – описание объектов, их совокупностей, отношений между ними и способов их взаимодействия Преимущества: • интуитивная близость к произвольной предметной области; • моделирование сколь угодно сложных предметных областей; • событийная ориентированность; © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Важным шагом на пути к совершенствованию языков программирования стало появление объектно-ориентированного подхода к программированию и соответствующего класса языков. В рамках данного подхода программа представляет собой описание объектов, их свойств (или атрибутов), совокупностей (или классов), отношений между ними, способов их взаимодействия и операций над объектами (или методов). Несомненным преимуществом данного подхода является концептуальная близость к предметной области произвольной структуры и назначения. Механизм наследования атрибутов и методов позволяет строить производные понятия на основе базовых и таким образом создать модель сколь угодно сложной предметной области с заданными свойствами. Еще одним теоретически интересным и практически важным свойством объектноориентированного подхода является поддержка механизма обработки событий, которые изменяют атрибуты объектов и моделируют их взаимодействие в предметной области.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Объектно-ориентированные языки программирования (2) Преимущества: • высокий уровень абстракции; • повторное использование описаний; • параметризация методов обработки объектов Недостатки: • сложность тестирования и верификации программ Примеры: C++, Visual Basic, C#, Eiffel, Oberon © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перемещаясь по иерархии классов от более общих понятий предметной области к более конкретным (или от более сложных – к более простым) и наоборот, программист получает возможность изменять степень абстрактности или конкретности взгляда на моделируемый им реальный мир. Использование ранее разработанных (возможно, другими коллективами программистов) библиотек объектов и методов позволяет значительно сэкономить трудозатраты при производстве программного обеспечения, в особенности, типичного. Объекты, классы и методы могут быть полиморфными, что делает реализованное программное обеспечение более гибким и универсальным. Сложность адекватной (непротиворечивой и полной) формализации объектной теории порождает трудности тестирования и верификации созданного программного обеспечения. Пожалуй, это обстоятельство является одним из самых существенных недостатков объектно-ориентированного подхода к программированию. Наиболее известным примером объектно-ориентированного языка программирования является язык C++, развившийся из императивного языка С. Его прямым потомком и логическим продолжением является язык С#. Другие примеры объектно-ориентированных языков программирования представлены на слайде.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Языки сценариев (1) Время появления: 1990-е г.г. Краткая характеристика: программа – совокупность описаний возможных сценариев обработки данных Преимущества: • интуитивная ясность; • близость к предметной области; • высокая степень абстракции; • высокая переносимость © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Развитием событийно управляемой концепции объектно-ориентированного подхода стало появление в 90-х г.г. целого класса языков программирования, которые получили название языков сценариев или скриптов. В рамках данного подхода программа представляет собой совокупность возможных сценариев обработки данных, выбор которых инициируется наступлением того или иного события (щелчок по кнопке мыши, попадание курсора в ту или иную позицию, изменение атрибутов того или иного объекта, переполнение буфера памяти и т.д.). События могут инициироваться как операционной системой (в частности, Windows), так и пользователем. Основные достоинства языков данного класса унаследованы от объектноориентированных языков программирования. Это интуитивная ясность описаний, близость к предметной области, высокая степень абстракции, хорошая переносимость.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Языки сценариев (2) Преимущества: • возможность повторного использования кода; • совместимость с инструментальными средствами автоматизированного проектирования (CASE) и быстрой разработки (RAD) прикладного программного обеспечения Недостатки: • сложность тестирования и верификации программ; • множественные побочные эффекты Примеры: VBScript, PowerScript, LotusScript, JavaScript © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Широкие возможности повторного использования кода также унаследованы сценарными языками от объектно-ориентированных предков. Существенной положительной чертой языков сценариев является их совместимость с передовыми инструментальными средствами автоматизированного проектирования и быстрой реализации программного обеспечения, или так называемыми CASE- (ComputerAided Software Engineering) и RAD- (Rapid Application Development) средствами. Одним из наиболее передовых инструментальных комплексов для быстрой разработки приложений является Microsoft Visual Studio .NET, изучение и использование его возможностей предстоит нам в данном курсе. Естественно, что вместе с достоинствами объектно-ориентированного подхода языки сценариев унаследовали и ряд недостатков. К последним прежде всего относятся сложность тестирования и верификации программ и возможности возникновения в ходе эксплуатации множественных побочных эффектов, проявляющихся за счет сложной природы взаимодействия объектов и среды, представленной интерфейсами с подчас многочисленными одновременно работающими пользователями программного обеспечения, операционной системой и внешними источниками данных. Характерные примеры сценарных языков программирования представлены на слайде.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Языки параллельных вычислений (1) Время появления: 1980-е г.г. Краткая характеристика: программа – совокупность описаний процессов, которые могут выполняться одновременно или псевдопараллельно Преимущества: • высокая вычислительная эффективность для больших программных систем (тысячи одновременно работающих пользователей или компьютеров); • высокая эффективность функционирования в системах реального времени (системы жизнеобеспечения и принятия решений) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Еще одним весьма важным классом языков программирования являются языки поддержки параллельных вычислений. Программы, написанные на этих языках, представляют собой совокупность описаний процессов, которые могут выполняться как в действительности одновременно, так и в псевдопараллельном режиме. В последнем случае устройство, обрабатывающее процессы, функционирует в режиме разделения времени, выделяя время на обработку данных, поступающих от процессов, по мере необходимости (а иногда с учетом последовательности или приоритетности выполнения операций). Языки параллельных вычислений позволяют достичь заметного выигрыша в эффективности при обработке больших массивов информации, поступающих, например, от одновременно работающих пользователей, либо имеющих высокую интенсивность (как, например, видеоинформация или звуковые данные высокого качества). Другой весьма значимой областью применения языков параллельных вычислений являются системы реального времени, в которых пользователю необходимо получить ответ от системы непосредственно после запроса. Системы такого рода отвечают за жизнеобеспечение и принятие ответственных решений.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Языки параллельных вычислений (2) Недостатки: • высокая себестоимость разработки относительно небольших программ (сотни строк кода); • относительно узкий спектр применения Примеры: Ada, Modula-2, Oz
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Обратной стороной достоинств рассматриваемого класса языков программирования является высокая стоимость разработки программного обеспечения, следовательно, разработка относительно небольших программ широкого (например, бытового назначения) зачастую нерентабельна. Примерами языков программирования с поддержкой параллельных вычислений могут служить Ada, Modula-2 и Oz.
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Подходы к программированию Основные подходы к программированию: • структурный, модульный; • функциональный; • логический; • объектно-ориентированный; • смешанный; • компонентно-ориентированный (.NET); • чисто объектный © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Итак, в данной лекции были рассмотрены история и эволюция языков программирования и основные подходы к разработке программных систем. Была сделана попытка классификации языков и подходов к программированию, а также проведен анализ достоинств и недостатков, присущих тем или иным подходам и языкам. Заметим, что приведенную классификацию не следует считать единственно верной и абсолютной, поскольку языки программирования постоянно развиваются и совершенствуются, и недавние недостатки устраняются с появлением необходимых инструментальных средств или теоретических обоснований. Подводя итого, кратко перечислим рассмотренные в течение лекции подходы к программированию: • ранние неструктурные подходы; • структурный или модульный подход (задача разбивается на подзадачи, затем на алгоритмы, составляются их структурные схемы и происходит реализация); • функциональный подход; • логический подход; • объектно-ориентированный подход; • смешанный подход (некоторые подходы возможно комбинировать); • компонентно-ориентированный (программный проект рассматривается как множество компонент, такой подход принят, в частности, в .NET); • чисто объектный подход (идеальный с математической точки зрения вариант, который пока не реализован практически).
Современные языки программирования и .NET: I семестр Лекция 1: Классификация языков программирования
Библиография 1. 2. 3. 4. 5.
Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).- Prentice Hall, 2000 Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).- McGraw-Hill, 1997 Peyton Jones S.L. The implementation of functional programming languages.- Prentice Hall, 1987 Landin P. The next 700 programming languages. Communications of ACM, 3, 1966 Gilmore S. Programming in Standard ML ’97: a tutorial introduction. http:/www.dcs.ed.ac.uk/home/stg © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках одной лекции невозможно в полном объеме представить картину развития языков и подходов к программированию. Мы ограничились рассмотрением лишь наиболее существенных для наших целей подходов, прежде всего, функционального и объектно-ориентированного. Для более детального ознакомления с последними достижениями и проблемами в области языков программирования, рекомендуется следующий список литературы: 1. Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).Prentice Hall, 2000 2. Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).McGraw-Hill, 1997 3. Peyton Jones S.L. The implementation of functional programming languages.- Prentice Hall, 1987 4. Landin P. The next 700 programming languages. Communications of ACM, 3, 1966 5. Gilmore S. Programming http:/www.dcs.ed.ac.uk/home/stg
in
Standard
ML
’97:
a
tutorial
introduction.
Кратко остановимся на источниках. В работе [1] приведен наиболее полный анализ истории развития и особенностей языков программирования с классификацией по областям применения. В работах [2-4] рассмотрены теоретические проблемы и практические аспекты реализации инновационных конструкций в языках программирования. Работа [5] посвящена описанию языка программирования Standard ML (или SML), изучение основ которого планируется в данном семестре.
Концепция и возможности подхода .NET
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к идеологии, технологии и обзору практических возможностей создания программных систем на основе наиболее современного подхода проектирования и реализации программного обеспечения, известного под названием Microsoft .NET.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8. 9.
.NET как идеология .NET как вычислительная модель .NET как технологическая платформа .NET как инструментальный комплекс Безопасность в .NET Интеграция приложений в .NET Поддержка веб-сервисов в .NET Достоинства и недостатки .NET Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В отличие от всех предшествующих подходов, компания Microsoft предлагает наиболее развитое и комплексное решение для проектирования и реализации программного обеспечения. В частности, в данной лекции будут рассмотрены такие аспекты .NET, как: • идеология; • вычислительная модель; • технологическая платформа; • инструментальное решение; • безопасность; • интеграция приложений; • поддержка веб-сервисов. В заключение будут проанализированы достоинства и недостатки .NET и сделаны необходимые выводы. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
Что такое .NET ? .NET сегодня – это: 1.
Идеология проектирования и реализации программного обеспечения
2.
Модель эффективной поддержки жизненного цикла прикладных систем
3.
Унифицированная, интегрированная технологическая платформа
4.
Современный, удобный в использовании, безопасный инструментарий для создания, размещения и поддержки программного обеспечения © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Прежде всего, необходимо ответить на важный вопрос: что такое .NET? Несмотря на широкое освещение в прессе, ответить однозначно непросто, прежде всего по той причине, что ответ представляется многоаспектным. Итак, можно сказать, что .NET – это подход к проектированию и реализации программного обеспечения, включающий по меньшей мере четыре следующих компонента: 1) идеология проектирования и реализации программного обеспечения; 2) модель эффективной поддержки жизненного цикла прикладных систем; 3) унифицированная, интегрированная технологическая платформа для программирования; 4) современный, удобный в использовании, безопасный инструментарий для создания, размещения и поддержки программного обеспечения. Остановимся подробнее на каждом из этих существенных аспектов.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET как идеология (vision) 1.
Легкость развертывания приложений в глобальной среде Интернет
2.
Экономичная разработка программного обеспечения
3.
«Бесшовная», гибкая интеграция программных продуктов и аппаратных ресурсов
4.
Предоставление программного обеспечения как сервиса
5.
Новый уровень безопасности и удобства использования © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Прежде всего, постараемся сформировать понимание идеологии подхода Microsoft .NET. Самой корпорацией-разработчиком сформулированы важнейшие аспекты видения (vision) идеологии .NET: 1) 2) 3) 4) 5)
приблизительно
следующие
легкость развертывания приложений в глобальной среде Интернет; экономичная разработка программного обеспечения; «бесшовная», гибкая интеграция программных продуктов и аппаратных ресурсов; предоставление программного обеспечения как сервиса; новый уровень безопасности и удобства использования.
Действительно, как мы увидим в ходе лекции, все аспекты видения .NET удалось реализовать на качественно новом уровне, обеспечив существенное продвижение вперед в направлении гибкости интеграции с программно-аппаратными ресурсами, безопасности и удобстве использования кода, а также снижении затрат на производство программного обеспечения.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET как вычислительная модель 1.
Компонентный подход как развитие объектноориентированной модели
2.
Универсальная система типизации: «всякая сущность есть объект»; унификация данных и метаданных
3.
Строго иерархическая организация кода, пространств имен и классов
4.
Универсальный интерфейс .NET Framework (включая поддержку различных подходов к программированию)
5.
Высокая вариативность экземпляров реализации (в частности, на основе веб-сервисов) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим подробнее, как идеология .NET претворяется в практические вопросы проектирования программного обеспечения. Корпорацией Microsoft предложен новаторский компонентно-ориентированный подход к проектированию, который является развитием объектно-ориентированного направления. Согласно этому подходу, интеграция объектов (возможно, гетерогенной природы), производится на основе интерфейсов, представляющих эти объекты (или фрагменты программ) как независимые компоненты. Такой подход существенно облегчает написание и взаимодействие программных «молекул»-компонент в гетерогенной среде проектирования и реализации. Стандартизируется хранение и повторное использование компонент программного проекта в условиях распределенной сетевой среды вычислений, где различные компьютеры и пользователи обмениваются информацией, например, взаимодействуя в рамках исследовательского или бизнес-проекта. Существенным преимуществом является и возможность практической реализации принципа «всякая сущность является объектом гетерогенной программной среды». Во многом это стало возможным благодаря усовершенствованной, обобщенной системе типизации Common Type System, или CTS, которая будет подробнее рассмотрена в одной из следующих лекций. Строгая иерархичность организации пространств для типов, классов и имен сущностей программы позволяет стандартизировать и унифицировать реализацию. Новый подход к интеграции компонент приложений в среде вычислений Интернет (или так называемые веб-сервисы), дает возможность ускоренного создания приложений для глобальной аудитории пользователей. Универсальный интерфейс .NET Framework обеспечивает интегрированное проектирование и реализацию компонент приложений, разработанных согласно различным подходам к программированию.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET как технологическая платформа 1.
Многоязыковая поддержка (десятки языков программирования)
2.
Использование технологии веб-сервисов для обеспечения интероперабельности и масштабируемости в глобальной сетевой среде
3.
Унификация доступа к библиотекам API-интерфейса независимо от языка и программной модели
4.
Соответствие современным технологическим стандартам © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Говоря о .NET как о технологической платформе, нельзя не отметить тот факт, что она обеспечивает одновременную поддержку проектирования и реализации программного обеспечения с использованием различных языков программирования. При этом поддерживаются десятки языков программирования, начиная от самых первых (в частности, COBOL и FORTRAN) и заканчивая самыми современными (например, C# и Visual Basic). Ранние языки программирования до сих пор активно используются, в частности, для обеспечения совместимости с ранее созданными приложениями, критичными для бизнеса (скажем, COBOL весьма широко использовался для создания прикладных программ, поддерживающих финансовую деятельность). Применение технологии веб-сервисов – это не просто дань моде на Интернет, а реальная (и, пожалуй, наиболее приемлемая практически возможность) обеспечения масштабируемости и интероперабельности приложений. Под масштабируемостью понимают возможность плавного роста времени ответа программной системы на запрос с ростом числа одновременно работающих пользователей; в случае веб-сервисов масштабируемость реализуется посредством распределения вычислительных ресурсов между сервером, на котором выполняется прикладная программа (или хранятся данные) и компьютером пользователя. Под интероперабельностью понимается возможность интегрированной обработки гетерогенных данных, поступающих от разнородных прикладных программ. Именно благодаря интероперабельности возможна унификация взаимодействия пользователей через приложение с операционной системой на основе специализированного интерфейса прикладных программ, или API-интерфейса (Application Programming Interface). Немаловажно отметить и то обстоятельство, что новая технология .NET не только востребована мировой общественностью, но и официально признана, что отражено в соответствующих стандартах ECMA (European Computer Manufacturers Association).
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET - универсальное инструментальное средство 1. 2. 3. 4. 5.
Поддержка многоязыковой среды CLR (Common Language Runtime) Возможность создавать компоненты проекта в единой среде на наиболее подходящем языке программирования Доступность всех средств .NET для каждого из широкого спектра языков программирования Сервисные возможности для разработчиков, (отладка, анализ кода, …) одинаковы для всех языков Возможность облегченной самостоятельной разработки транслятора для любого языка программирования (Microsoft – VB, C#, … другие – APL, COBOL, Eiffel, Fortran, Haskell, SML, Perl, Python, Scheme, Smalltalk, …)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Теперь рассмотрим инструментальные возможности .NET как средства проектирования и реализации программного обеспечения, т.е., собственно, программирования в широком смысле этого слова. Прежде всего, необходимо отметить поддержку многоязыковой среды разработки приложений CLR (Common Language Runtime). Эта возможность появилась благодаря универсальному межъязыковому интерфейсу Common Language Infrastructure, или CLI, который поддерживает разработку программных компонент на различных языках программирования. При этом несомненным преимуществом для программистов является то обстоятельство, что они могут разрабатывать (или дорабатывать) программное обеспечение на наиболее подходящем языке программирования. Здесь следует учитывать характер задачи (скажем, рекурсия или символьная обработка прозрачнее и с меньшими трудозатратами реализуема на языке функционального программирования, а формализация структуры предметной области – на объектно-ориентированном языке). Кроме того, необходимо принимать во внимание опыт работы программистов в команде разработчиков и тот язык программирования, на котором изначально создавалась система. Отметим еще два существенных обстоятельства. Во-первых, основные сервисные возможности для разработчиков, которые предоставляет среда .NET, (отладка, анализ кода и т. д.) не зависят от конкретного языка программирования, и, следовательно, программистам нет необходимости заново постигать особенности среды разработки, если необходимо перейти с одного языка на другой. Во-вторых, несмотря на то, что еще не все языки программирования поддерживаются .NET, существует возможность самостоятельной разработки транслятора для любого языка программирования, причем его реализация не вызывает трудностей даже у программистов, практически не имеющих профессиональной подготовки в области разработки компиляторов.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET - безопасное инструментальное средство (1) •
Автоматизированное управление жизненным циклом программного обеспечения: • автоматическая «сборка мусора»; • запрет «висячих» и циклических ссылок
•
Обеспечение синтаксической корректности кода: • безопасные вызовы функций и процедур; • контроль выхода за границы массива: • запрет использования переменных без инициализации © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Важнейшим элементом любой идеологии, технологии и инструментального средства программирования в настоящее время является безопасность. Это утверждение неоспоримо, если принять во внимание тот факт, что многие важнейшие системы жизнеобеспечения и оборонной отрасли управляются автоматизированным образом, т.е. с помощью компьютеров. В этой связи .NET как инструментальное средство призвано обеспечивать уровень безопасности, отвечающий современным требованиям. Для этого в .NET реализована, в частности, такая мера безопасности, как автоматизированное управление жизненным циклом программного обеспечения. Для программиста это проявляется, например, в автоматической реализации процедуры «сборки мусора», а также в запрете на использования указателей на области памяти с неопределенным значением («висячих» ссылок) и самоссылающихся указателей (циклических ссылок). Более существенным ограничением безопасности является автоматизация обеспечения синтаксической коррекции кода. Это достигается посредством безопасных вызовов функций и процедур, контроля выхода за границы заявленного программистом размера статически распределяемых областей памяти, а также запрета использования переменных без задания им значения по умолчанию (инициализации).
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET - безопасное инструментальное средство (2) •
•
•
Расширенный контроль соответствия типов (проверка промежуточного кода (IL – Intermediate Language) на корректность типизации) Гибкое и надежное разграничение прав доступа к данным: • проверка подлинности кода; • политики доступа к ресурсам Криптографические методы обеспечения безопасности доступа к данным © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Еще одним важным аспектом комплексного обеспечения безопасности в .NET является обязательная проверка промежуточного кода (IL – Intermediate Language) на корректность типизации, которая осуществляется в рамках реализованной стратегии расширенного контроля соответствия типов. Существенное нововведение добавлено и к правам доступа пользователей к ресурсам. В частности, для включения компонента в проект необходимо проверить источник кода, заверенный автором цифровой подписью, и убедиться в подлинности отправителя. Гибкое и надежное ограничение доступа пользователей к ресурсам осуществляется также благодаря широкому спектру динамически корректируемых в соответствии с профилями пользователя политик доступа. Немаловажным пунктом для обеспечения безопасности являются и криптографические методы, которые необходимы для шифрования конфиденциальной или коммерческой информации, передаваемой, например, по Интернет-каналам.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET – интегрированное средство разворачивания и поддержки приложений 1.
Сборка (assembly) – набор модулей для установки: • уникальность (номер версии, цифровая подпись); • самодостаточность; • локальное или коллективное многократное использование (компонентная технология); • минимальные затраты на установку. 2. Манифест (manifest) – описание сборки: • идентификация автора и версии сборки; • режим и политика использования сборки. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение поддержки жизненного цикла рамках подхода .NET.
программного обеспечения в
Для установки на компьютеры пользователей ранее созданного прикладного программного обеспечения создаются инсталляционные комплекты в форме так называемых сборок. Сборкой называется множество модулей, необходимых для осуществления инсталляции программного обеспечения. Сборка характеризуется уникальностью, которая обеспечивается идентификатором версии сборки и цифровой подписью автора. Сборка является самодостаточной единицей для установки программного обеспечения и не требует никаких дополнений. Возможно как индивидуальное, так и коллективное (сетевое) использование сборки на основе компонентной технологии. Сборка обеспечивает простой и удобный механизм инсталляции и экономит средства на разворачивания программного обеспечения, сводя к минимуму затраты времени и труда на установку. Описание сборки содержится в так называемом манифесте, где хранятся идентификация автора и версии сборки, а также режим и политика использования последней.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET – интернет-ориентированная среда 1.
Основные цели развития интернет-сервисов: • интерактивная обработка документов пользователями; • совместная работа пользователей с приложениями; • поддержка взаимодействия приложений;
2.
Адаптация интернет-среды для интеграции приложений: • унификация информационной инфраструктуры; • обеспечение интероперабельности; • обеспечение масштабируемости. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Современное общество вступило в эру Интернет-коммуникации, т.е. в самое ближайшее время практически каждый человек сможет получать доступ к распределенным ресурсам глобальной сети из любой точки Земли. В этой связи в .NET реализована концепция веб-сервисов как средства поддержки распределенных компонентных вычислений в глобальной сети. При этом наиболее существенными задачами, решение которых необходимо обеспечить, являются следующие: • интерактивная обработка пользователями информации (документов, таблиц, графики и т.д.), представленной в электронной форме; • организация совместной работы пользователей с прикладным программным обеспечением (заседания рабочих групп, конференции и т.д.); • поддержка взаимодействия прикладных программ друг с другом. В этой связи, в концепции .NET сформулирована и решена задача адаптации изначально аморфной и практически не структурированной Интернет-среды для достижения возможности интеграции приложений. Основные направления решения этой задачи кратко сводятся к следующим: • унификация информационной инфраструктуры; • достижение необходимого уровня интероперабельности прикладного программного обеспечения; • достижение необходимого уровня масштабируемости прикладного программного обеспечения.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET – интероперабельный подход • • • • •
Универсальная высокоуровневая языковая среда Common Language Infrastructure (CLI): поддержка различных подходов к программированию (функциональный, объектный, веб-ориентированный, ...); общее управление оперативной памятью (сборка мусора, тестирование кода на безопасность); единая система типов (Common Type System, CTS), включающая общую иерархию для примитивных типов, типов-значений и ссылочных типов; унифицированный механизм обработки исключительных ситуаций; среда разработки обеспечивает межъязыковую отладку. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Задача достижения необходимого уровня масштабируемости прикладного программного обеспечения является достаточно сложной технически и выходит за рамки данного учебного курса. Задача поддержки интероперабельности прикладного программного обеспечения в рамках концепции .NET решается с помощью универсальной высокоуровневой языковой среды Common Language Infrastructure (CLI), которая характеризуется следующими возможностями. Во-первых, осуществляется поддержка разнообразных языков программирования, а, следовательно, и различных подходов к программированию, в частности, функционального (например, на основе SML, Scheme, Haskell), объектноориентированного (например, на основе С++) и компонентного (например, на основе С#) подходов. Затем, интегрированное использование языков программирования осуществляется совместно с единой системой типов (Common Type System, CTS), включающей общую иерархию для примитивных типов, типов-значений и ссылочных типов. Управление оперативной памятью также реализовано в .NET в обобщенном варианте. В частности, централизовано осуществляются сборка мусора и тестирование кода на безопасность с точки зрения взаимодействия с оперативной памятью. Механизм обработки исключительных ситуаций также унифицирован. Наконец, универсальная высокоуровневая языковая среда Common Language Infrastructure обеспечивает межъязыковую отладку.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET – решение, подтвержденное стандартами • • • • •
язык программирования C# и Common Language Infrastructure (CLI) ратифицированы организацией ECMA в качестве международного стандарта; заключено соглашение о сотрудничестве между Microsoft, Intel и Hewlett-Packard; ряд сторонних компаний ведет проекты в соответствии со спецификациями ECMA (в частности, реализация .NET под управлением операционной системы Linux); Microsoft планирует совместную разработку программного проекта .NET под управлением операционных систем FreeBSD Windows; http://msdn.microsoft.com/net/ecma/ © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для любого тиражируемого коммерческого программного продукта необходимо подтверждение его соответствия общепринятым в мировой практике программирования стандартам. В отношении технологий .NET теоретические достижения и технологические инновации подтверждаются мнением европейской ассоциации по стандартам ECMA (European Computer Manufacturers Association). Так, язык программирования C# и Common Language Infrastructure (CLI) ратифицированы организацией ECMA в качестве международного стандарта. Кроме того, ряд сторонних компаний-разработчиков программного обеспечения ведет проекты в соответствии со спецификациями ECMA (в частности, реализация .NET под управлением операционной системы Linux). Ведущие производители аппаратного и программного обеспечения составляют рассчитывают на .NET как на стратегический путь совместного с Microsoft развития. В частности, в 2001 году подписано соглашение о сотрудничестве между Microsoft, Intel и Hewlett-Packard. Вопреки распространенному мнению, Microsoft не настаивает на непременном условии единственности операционной системы Windows для поддержки .NET. Корпорация планирует совместную разработку программного проекта .NET под управлением операционных систем FreeBSD и Windows. Более подробную информацию о стандартизации технологий и программного обеспечения семейства .NET можно получить из Интернет-сайта, расположенного по следующему адресу: http://msdn.microsoft.com/net/ecma/ .
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
.NET – наиболее существенные недостатки 1. 2. 3. 4.
Высокие требования к аппаратному обеспечению (минимум 256M RAM, 10G HDD для работы с Microsoft Visual Studio .NET) Сложности работы с не коммерческими релизами программного обеспечения (некоторая неустойчивость, отсутствие полномасштабной документации); Поддержка ряда теоретически интересных и практически полезных языков программирвоания не в полном объеме (SML для Visual Studio .NET – в процессе реализации); Инструментарий .NET (и компиляторы для языков программирования) не ратифицированы по международным стандартам. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Несмотря на перечисленные выше инновации в области теории, технологии и практической реализации, в силу масштабности идеологии и новизны исследуемой проблематики, подход .NET не лишен отдельных недостатков, большинство из которых, по-видимому, носит временный характер. Отметим, по нашему мнению, наиболее существенные из них. Во-первых, разработчики отмечают достаточно высокие требования к аппаратному обеспечению (в частности, объем оперативной памяти должен быть не менее 256 мегабайт, свободный объем жесткого диска для работы с Microsoft Visual Studio .NET – не менее 10 гигабайт). Кроме того, некоммерческие версии программных продуктов Microsoft, которые зачастую предоставляют новые существенные возможности, в недостаточной степени устойчивы в работе; документация по ряду новых функций программного обеспечения представлена не в полном объеме. Поддержка ряда теоретически интересных и практически полезных языков программирования реализована в ограниченном объеме (скажем, компилятор для языка программирования SML для Visual Studio .NET находится в процессе реализации). Поскольку целый ряд компиляторов для языков программирования предоставляется сторонними по отношению к Microsoft компаниями-разработчиками или некоммерческими учреждениями, результаты их деятельности поддаются контролю и доработке с ограничениями. Комплекс программно-инструментальных средств, реализующий подход .NET (включая и компиляторы для языков программирования) ратифицирован по международным стандартам не в полном объеме.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
Платформа .NET – выводы 1.
Стратегическая идеология и технологическая платформа Microsoft на ближайшее десятилетие 2. Несомненное качественное превосходство над аналогами (Inprise Delphi, Microsoft Visual Studio и др.) за счет: • интероперабельности и межъязыкового взаимодействия; • многоуровневой безопасности; • интеграции с веб-сервисами; • облегчения разворачивания и использования. 3. Некоторая незавершенность решения для широкого коммерческого использования в силу концептуальной новизны и грандиозности проекта. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко резюмируем итоги лекции. Безусловно, .NET является выдающимся достижением современной индустрии программирования. Достаточно сказать, что корпорация Microsoft считает именно .NET своей стратегической идеологией и технологической платформой на ближайшее десятилетие. Несомненное качественное превосходство над существующими средствами автоматизированного проектирования и быстрой реализации прикладного программного обеспечения (в частности, Inprise Delphi и JBuilder, Oracle Developer, Microsoft Visual Studio и др.) достигается за счет следующих основных факторов: • интероперабельность и межъязыковое взаимодействие; • многоуровневая, гибкая и надежная политика безопасности; • интеграция с технологией веб-сервисов; • упрощение процедуры разворачивания и использования создаваемого программного обеспечения. Несмотря на некоторую незавершенность решения для широкого коммерческого использования в силу концептуальной новизны и грандиозности проекта, подход .NET, безусловно, оказывает значительное влияние на коммерческую индустрию программирования в целом и способствует радикальному совершенствованию отрасли в ходе рыночной конкуренции.
Современные языки программирования и .NET: I семестр Лекция 2: Концепция и возможности подхода .NET
Библиография 1. 2. 3. 4. 5.
http://msdn.microsoft.com/net Nathan A. .NET and COM: The Complete Interoperability Guide. Sams, 2002, 1608 pp. Box D. Essential .NET, Vol.1: The Common Language Runtime. Addison Wesley, 2002, 432 pp. Grimes F. Microsoft .NET for Programmers. Manning Publications, 2002, 386 pp. J. Richter. Applied Microsoft .NET Framework Programming. Microsoft Press, 2002, 556 pp. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках одной лекции невозможно представить такой многоаспектный подход как .NET в полном объеме. Для более детального ознакомления с последними достижениями и проблемами в ходе развития подхода и полученных результатов рекомендуется следующий список литературы: 1.http://msdn.microsoft.com/net 2. Nathan A. .NET and COM: The Complete Interoperability Guide. Sams, 2002, 1608 pp. 3. Box D. Essential .NET, Vol.1: The Common Language Runtime. Addison Wesley, 2002, 432 pp. 4. Grimes F. Microsoft .NET for Programmers. Manning Publications, 2002, 386 pp. 5. Richter J. Applied Microsoft .NET Framework Programming. Microsoft Press, 2002, 556 pp. Кратко остановимся на источниках. Последние сведения о .NET из первых рук доступны с Интернет-ресурса [1]. Работы [2,3] посвящены интероперабельности; в работах [4,5] рассмотрены проблемы практической реализации программного обеспечения согласно подходу .NET.
Функциональный подход к программированию
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к истории развития, идеологии, математическому обоснованию и обзору возможностей программных систем на основе функционального подхода к проектированию и реализации программного обеспечения.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Содержание лекции 1. 2. 3. 4. 5.
Основы функционального подхода к программированию Классификация языков функционального программирования Преимущества языков функционального программирования Преимущества использования SML под управлением .NET Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к математическому обоснованию функционального подхода к программированию, а также исследовано своеобразие функционального подхода по сравнению с другими направлениями проектирования и реализации программного обеспечения, известными на сегодня. Далее будет представлен вариант классификации языков функционального программирования на основе реализованных в них теоретически важных свойств и практически полезных механизмов (в частности, полиморфизма и сопоставления с образцом). На основе классификации будут сделаны выводы о преимуществах и недостатках рассмотренных языков и подхода в целом для реализации тех или иных классов практических задач. Существенное внимание будет уделено языку функционального программирования SML, который изучается на протяжении всего курса, его истории развития, особенностям, а также его практической реализации на технологической платформе .NET. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Подходы к программированию • • • • • • •
структурный, модульный; функциональный; логический; объектно-ориентированный; смешанный; компонентно-ориентированный (.NET); чисто объектный
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним классификацию подходов к программированию, построенную нами в ходе вступительной лекции: • ранние неструктурные подходы; • структурный или модульный подход (задача разбивается на подзадачи, затем на алгоритмы, составляются их структурные схемы и происходит реализация); • функциональный подход (в основе лежит понятие функции); • логический подход (в основе лежат логические высказывания или правила в форме предикатов); • объектно-ориентированный подход (базируется на идее объекта); • смешанный подход (некоторые подходы возможно комбинировать); • компонентно-ориентированный (программный проект рассматривается как множество компонент, такой подход принят, в частности, в .NET); • чисто объектный подход (идеальный с математической точки зрения вариант, который пока не реализован практически).
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Функциональный подход к программированию Время появления: • теория: 1920-30-е г.г.; • первая реализация: 1950-е г.г. Основная особенность: программа – функция, аргументы которой, возможно, также являются функциями Примеры: LISP (1950-e) , ML (1970-e) , SML (1980-e), Scheme, Hope, Miranda, Clean, Haskell (1990-е) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Сосредоточимся на важнейшем для данного семестра функциональном подходе к программированию. Прежде всего, обратимся к истории фундаментальных математических исследований, которые привели к появлению функционального подхода к программированию. Время появления теоретических работ, которые обосновывают функциональный подход, относится к 20-м – 30-м годам XX столетия. Как мы увидим впоследствии, теория часто значительно опережает практику программирования, и важнейшие работы, которые сформировали математическую основу подхода, были созданы задолго до появления компьютеров и языков программирования, которые потенциально могли бы реализовать эту теорию. Что касается первой реализации, она появилась в 50-х годах XX столетия в форме языка LISP, о котором речь пойдет далее. Напомним, что важнейшей характеристикой функционального подхода является то обстоятельство, что всякая программа, разработанная на языке функционального программирования, может рассматриваться как функция, аргументы которой, возможно, также являются функциями. Функциональный подход породил целое семейство языков, родоначальником которых, как уже отмечалось, стал язык программирования LISP. Позднее, в 70-х годах, был разработан первоначальный вариант языка ML, который впоследствии развился, в частности, в SML, а также ряд других языков, из которых, пожалуй, самым «молодым» является созданный уже совсем недавно, в 90-х годах, язык Haskell.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Математические основания функционального подхода 1.
2. 3.
4.
Моделирование функций: теория конечных последовательностей – ламбда-исчисление А.Черча (Alonso Church) Моделирование типов: ламбда-исчисление с типами Моделирование среды вычислений в форме абстрактной машины - теория категорий Х. Карри (Haskell B. Curry) в форме категориальной комбинаторной логики Моделирование вычисления значения – теория решеток Д. Скотта (Dana S. Scott) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Истоки математических основ функционального подхода к программированию следует искать в ранних работах М. Шенфинкеля (Moses Schönfinkel), которые, нужно отметить, малоизвестны, т.к. довольно далеки по времени от работ, непосредственно связанных с функциональным подходом. Не вызывает сомнений тот факт, что разработанная А. Черчем (Alonso Church) теория конечных последовательностей в форме исчисления ламбда-конверсий (или, короче, ламбда-исчисления), которое будет рассмотрено подробнее в следующей лекции, положила начало математическому исчислению, формализующему понятие функции. Дальнейшее развитие функциональный подход получает в работах, посвященных типизированному ламбда-исчислению, согласно которым аргументам функций и самим функциям можно назначать (или, иначе, приписывать) тот или иной тип. Типизация существенно увеличивает вычислительную стройность и значимость любой математической формализации, и, естественно, без нее немыслимы современные языки программирования. Проблемы и особенности типизации будут подробно рассмотрены в одной из последующих лекций. Теорию и практику программирования существенно обогатило моделирование среды вычислений в форме абстрактной машины, построенной на основе категориальной комбинаторной логики, созданной Х. Карри (Haskell B. Curry), в честь которого, кстати, и назван язык Haskell. Заметим, что абстрактные (или, иначе, виртуальные) машины являются основой для реализации языка SML и платформы .NET. Наконец, теория решеток Д. Скотта (Dana S. Scott) стала основой для моделирования вычисления значения функции (или семантики) языка программирования.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Функциональный подход: преимущества 1.
Полностью автоматическое управление памятью компьютера («сборка мусора») 2. Простота повторного использования фрагментов кода 3. Расширенная поддержка параметрических функций 4. Абстрагирование от машинного представления данных (система счисления, способы хранения и поиска) 5. Прозрачность реализации самоприменяемых (рекурсивных) функций
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Важным преимуществом реализации языков функционального программирования является автоматизированное динамическое распределение памяти компьютера для хранения данных. При этом программист избавляется от рутинной необходимости контролировать данные, а при необходимости может запустить функцию «сборки мусора» – очистки памяти от тех данных, которые больше не потребуются программе. Сложные программы при функциональном подходе строятся посредством агрегирования функций. При этом текст программы представляет собой функцию, некоторые аргументы которой можно также рассматривать как функции. Таким образом, повторное использование кода сводится к вызову ранее описанной функции, структура которой, в отличие от процедуры императивного языка, прозрачна математически. Типы отдельных переменных функций, используемых в функциональных языках, могут быть переменными. При таком подходе обеспечивается возможность обработки разнородных данных (например, упорядочение элементов списка по возрастанию для целых чисел, отдельных символов и строк) или полиморфизм. Таким образом, при создании программ на функциональных языках программист сосредотачивается на предметной области и в меньшей степени заботится о рутинных операциях (обеспечении правильного с точки зрения компьютера представления данных, «сборке мусора» и т.д.). Поскольку функция является естественным формализмом для языков функционального программирования, реализация различных аспектов программирования, связанных с функциями, существенно упрощается. Интуитивно прозрачным становится написание рекурсивных функций, т.е. функций, вызывающих самих себя в качестве аргумента. Естественной становится и реализация обработки рекурсивных структур данных. Благодаря реализации механизма сопоставления с образцом, такие языки функционального программирования как ML и Haskell весьма хорошо применимы для символьной обработки.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Функциональный подход: недостатки 1. 2.
3.
Нелинейная структура программы Необходимость фундаментальной математической подготовки разработчиков (достаточно хорошее понимание природы функций) Относительно невысокая эффективность для некоторых классов задач
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Естественно, языки функционального программирования не лишены и некоторых недостатков. Часто к ним относят нелинейную структуру программы и относительно невысокую эффективность реализации. Однако, первый недостаток достаточно субъективен, а второй успешно преодолен современными реализациями, в частности, рядом последних трансляторов языка SML, включая и компилятор для среды Microsoft .NET. Для профессиональной разработки программного обеспечения на языках функционального программирования необходимо глубоко понимать природу функции. Исследованию закономерностей и особенностей природы функции, в основном, и посвящен первый семестр данного курса.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Функция в математике и программировании Математической функцией f с областью определения A и областью значений B называется множество упорядоченных пар (a,b)∈A×B, таких что если (a,b1)∈f и (a,b2)∈f, то b1=b2. Функцией в языке программирования называется конструкция этого языка, описывающая правила преобразования аргумента (т.н. фактического параметра) в результат.
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Прежде всего, заметим, что под термином «функция» в математической формализации и программной реализации имеются в виду различные понятия. Так, математической функцией f с областью определения A и областью значений B называется множество упорядоченных пар (a,b) ∈ A×B, таких, что если (a,b1) ∈ f и (a,b2) ∈f, то b1=b2. В свою очередь, функцией в языке программирования называется конструкция этого языка, описывающая правила преобразования аргумента (так называемого фактического параметра) в результат.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Общие сведения о λ-исчислении Ламбда-исчисление – математическая теория, предназначенная для формализации обозначения и переобозначения (или, иначе, конверсии). Конверсии фактически являются важнейшим предметом практического программирования Классическая бинарная (булева) логика, а также большинство других разделов математики, неудовлетворительны для решения данной проблемы
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для формализации понятия «функция» была построена математическая теория, известная сегодня под названием ламбда-исчисления. Более точно это исчисление следует называть исчислением ламбда-конверсий. Под конверсией понимается преобразование объектов исчисления (а в программировании – функций и данных) из одной формы в другую. Исходной задачей в математике было стремление к упрощению формы выражений. В программировании именно эта задача не является столь существенной, хотя, как мы увидим в дальнейшем, использование ламбдаисчисления как исходной формализации может способствовать упрощению вида программы, т.е. вести к оптимизации программного кода. Кроме того, конверсии обеспечивают переход к вновь введенным обозначениям и, таким образом, позволяют представлять предметную область в более компактном или более детальном виде, или, говоря математическим языком, изменять уровень абстракции по отношению к предметной области. Эту возможность широко используют также языки объектно-ориентированного и структурно-модульного программирования в иерархии объектов, фрагментов программ и структур данных. На этом же принципе основано взаимодействие компонентов приложения в .NET. Именно в этом смысле переход к новым обозначениям является одним из важнейших элементов программирования в целом, и именно ламбда-исчисление (в отличие от многих других разделов математики), как оказывается, является адекватным способом формализации переобозначений.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
История развития функционального подхода (1) 1924 – М. Шенфинкель (Moses Shönfinkel) разработал простую (simple) теорию функций 1934 – А. Черч (Alonso Church) предложил ламбда-исчисление и применил его для разработки теории множеств 1940 – Х. Карри (Haskell Curry) предложил теорию функций без переменных, известную как комбинаторная логика © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Систематизируем эволюцию теорий, лежащих в основе современного подхода к ламбдаисчислению. Еще в 1924 году М. Шенфинкель (Moses Shönfinkel) разработал простую (simple) теорию функций, которая фактически являлась исчислением объектов-функций и предвосхитила появление ламбда-исчисления. Затем, в 1934 году, А. Черч (Alonso Church) предложил собственно исчисление ламбдаконверсий или ламбда-исчисление и применил его для исследования теории множеств. Вклад ученого был настолько фундаментальным, что теория до сих пор называется ламбда-исчислением и часто именуется в литературе ламбда-исчислением Черча. Позднее, в 1940 году, Х. Карри (Haskell Curry) предложил теорию функций без переменных (иначе называемых комбинаторами), известную в настоящее время как комбинаторная логика. Эта теория является развитием ламбда-исчисления и представляет собой формальный язык, аналогичный языку функционального программирования и позволяющий более наглядно моделировать вычисления в среде абстрактных машин, в значительной мере схожих с виртуальной машиной .NET.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
История развития функционального подхода (2) 1960-е - Р. Хиндли (Roger Hindley) разработал выводимость типов (type inference) 1960-е – П. Лендин (Peter Landin) создал абстрактную машину SECD, формализующую язык ISWIM (If you See What I Mean) - прообраз языка функционального программирования ML 1970-e – Р. Милнер (Robin Milner) создал полиморфную систему типов для языка функционального программирования ML © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Позднее, уже в 60-х г.г. Р. Хиндли (Roger Hindley) разработал выводимость типов (type inference), т.е. возможность неявно определить тип выражения, исходя из типов выражений, которые его окружают. Именно эта возможность широко используется в современных языках программирования, таких как SML и Haskell. Также в 60-х г.г. П. Лендин (Peter Landin) создал первую абстрактную машину на основе расширенного ламбда-исчисления. Машина получила название SECD и формализовала вычисления на языке программирования ISWIM (If you See What I Mean), который впоследствии стал прообразом языка функционального программирования ML. Наконец, в 70-х г.г. Р. Милнер (Robin Milner) создал полиморфную систему типизации для языка функционального программирования ML, которая вместе с развернутым описанием того же автора положила начало стандартизации этого языка программирования. Язык ML впоследствии эволюционировал по нескольким направлениям, мы будем изучать SML – ту его ветвь, которая развита Р. Милнером.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Классификация языков функционального программирования 1. 2. 3. 4.
Бестиповые языки: классический LISP Языки со строгой типизацией: ML Языки с полиморфной типизацией: SML, Miranda, Haskell Языки «нового поколения» с широкими возможностями: • сопоставление с образцом (Scheme, SML, Miranda, Haskell) • параметрический полиморфизм (SML) • «ленивые» вычисления (Haskell, Miranda, SML) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим эволюцию языков функционального подхода.
программирования,
развивающихся
Ранние языки функционального программирования, которые берут классического языка LISP (LISt Processing), были предназначены, названия, для обработки списков, т.е. символьной информации. При типами были атомарный элемент и список из атомарных элементов, а делался на анализ содержимого списка.
в
рамках
свое начало от как явствует из этом основными основной акцент
Развитием ранних языков программирования стали языки функционального программирования с сильной типизацией, характерным примером которых является классический ML, и далее, его прямой потомок, SML. В языках с сильной типизацией каждая конструкция (или выражение) должно иметь тип. При этом в более поздних языках функционального программирования, однако, нет необходимости явного приписывания типа, и типы изначально неопределенных выражений, как в SML, могут выводиться (до запуска программы), исходя из типов связанных с ними выражений. Следующим шагом в развитии языков функционального программирования стала поддержка полиморфных функций, т.е. функций с параметрическими аргументами (аналогами математической функции с параметрами). В частности, полиморфизм поддерживается в языках SML, Miranda и Haskell. На современном этапе развития возникли языки функционального программирования «нового поколения» со следующими расширенными возможностями: сопоставление с образцом (Scheme, SML, Miranda, Haskell), параметрический полиморфизм (SML) и так называемые «ленивые» (по мере необходимости) вычисления (Haskell, Miranda, SML).
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Семейство языков функционального программирования ML 1.
«Классический» ML – создан Р. Милнером в MIT, США (строгая типизация, без параметрического полиморфизма) 2. SML – Cambridge, MIT, Edinburgh 3. CaML – разработан в INRIA, Франция 4. SML/NJ – диалект SML из New Jersey 5. mosml – «московский» диалект ML, разработан в России Диалекты SML 2-4 обладают примерно одинаковыми расширенными возможностями (полиморфизм, сопоставление с образцом, «ленивые» вычисления) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Семейство языков функционального программирования достаточно многочисленно. Это очевидно не столько из значительного списка языков, сколько из того факта, что многие языки дали начало целым направлением в программировании. Напомним, что LISP дал начало целому семейству языков: Scheme, InterLisp, COMMON Lisp и др. Не стал исключением и изучаемый нами язык программирования SML, который был создан в форме языка ML Р. Милнером в MIT (Massachusetts Institute of Technology), США и первоначально предназначен для логических выводов, в частности, доказательства теорем. Язык отличается строгой типизацией, в нем отсутствует параметрический полиморфизм. Развитием «классического» ML стали сразу три современных языка с практически одинаковыми возможностями (параметрический полиморфизм, сопоставление с образцом, «ленивые» вычисления). Это – язык SML, разработанный в Великобритании и США, CaML, созданный группой французских ученых института INRIA, SML/NJ – диалект SML из New Jersey, а также российская разработка – mosml («московский» диалект ML).
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Преимущества языков функционального программирования 1. 2. 3. 4. 5.
Простота верификации программного кода Унификация представления программы и данных Безопасная типизация – недопустимые операции над данными исключены Динамическая типизация – возможно обнаружение ошибок типизации во время выполнения программы Независимость программной реализации от машинного представления данных и системной архитектуры © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Близость к математической формализации и изначальная функциональная ориентированность являются причиной следующих преимуществ функционального подхода: 1) простота тестирования и верификации программного кода на основе возможности построения строгого математического доказательства корректности программ; 2) унификация представления программы и данных (данные могут быть инкапсулированы в программу как аргументы функций, означивание или вычисление значения функции может производиться по мере необходимости) ; 3) безопасная типизация: недопустимые операции над данными исключены; 4) динамическая типизация: возможно обнаружение ошибок типизации во время выполнения (это свойство ранних языков функционального программирования может приводить к переполнению оперативной памяти компьютера); 5) независимость программной реализации от машинного представления данных и системной архитектуры программы (программист концентрирует внимание на деталях реализации, а не особенностях машинного представления данных).
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Преимущества SML (1) •
•
•
Безопасность кода – гарантия отсутствия переполнения памяти и взлома системы (C и C++ потенциально небезопасны) Статическая типизация: выявление ошибок несоответствия типов на этапе трансляции (в LISP и Scheme это невозможно) Выводимость типов – типы необязательно указывать явно, код легче читается, хранится и повторно используется © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду По сравнению с другими языками программирования, в том числе с ранними функциональными языками, SML обладает рядом несомненных достоинств. К ним, в первую очередь, относятся: 1) безопасность программного кода, т.е. гарантия отсутствия переполнения памяти (в случае корректно написанной программы) и, соответственно, защиты от потенциальной неустойчивости работы системы посредством искусственного создания этого переполнения (такие языки программирования, как «классический» C и C++ потенциально небезопасны); 2) статическая типизация: все ошибки несоответствия типов выявляются уже на стадии контроля соответствия типов в ходе трансляции (а не во время выполнения программы, как в LISP и Scheme); 3) Выводимость типов (нет необходимости явно указывать тип каждого выражения, при этом результирующий программный код становится более удобочитаемым, его легче хранить и повторно использовать).
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Преимущества SML (2) •
• • •
Параметрический полиморфизм – функции могут обрабатывать аргументы любого типа, экономятся трудозатраты Сопоставление с образцом – мощное средство декомпозиции и верификации программ Модульная структура – интерфейс и реализация разделены Исключения, продолжения – критичны для систем реального времени © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К числу других преимуществ языка функционального программирования SML следует отнести параметрический полиморфизм (возможность обрабатывать аргументы абстрактного типа). При этом трудозатраты на разработку программного обеспечения сокращаются за счет универсальности разрабатываемых функций (скажем, становится возможным написать унифицированную функцию для упорядочения по возрастанию элементов списка, которая сможет упорядочивать и список из целочисленных элементов, и список из символьных строк). Еще одним мощным средством, облегчающих символьную обработку (в частности, декомпозицию и верификацию программ), является механизм сопоставления с образцом. Построение программ из модулей способствует разделению интерфейсной части (описательной части) и реализации (содержательной части) функций, что обеспечивает унификацию и сокращает время создания сложных программных проектов, облегчая тестирование на соответствие спецификациям заказчика. Обработка исключительных ситуаций, которые описывают ход выполнения программы в случае возникновения тех или иных относительно редких событий, а также теоретически интересного механизма продолжений, создают возможность реализации программных систем, взаимодействующих с пользователем в реальном времени.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Преимущества разработки программного обеспечения под управлением Microsoft .NET 1.
2.
3. 4.
Интеграция различных языков функционального программирования (Scheme – сопоставление с образцом, SML – «ленивость») Интеграция различных подходов к программированию на основе Common Language Infrastructure, CLI (C# – объектно-ориентированный, SML – функциональный) Общая система типизации CTS (Common Type System) Многоступенчатая, гибкая систем обеспечения безопасности программного кода © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Заметим, что реализация преимуществ, которые предоставляют языки функционального программирования, существенно зависит от выбора программно-аппаратной платформы. В случае выбора в качестве программной платформы технологии .NET, практически вне зависимости от аппаратной реализации, программист или руководитель программного проекта дополнительно получает следующие преимущества: 1) интеграция различных языков функционального программирования (при этом максимально используются преимущества каждого из языков, в частности, Scheme предоставляет механизм сопоставления с образцом, а SML – «ленивость» или вычисления по мере необходимости); 2) интеграция различных подходов к программированию на основе межъязыковой инфраструктуры Common Language Infrastructure, или CLI (в частности, использование C# для обеспечения преимуществ объектно-ориентированного подхода и SML – функционального, как в настоящем курсе); 3) общая система типизации Common Type System, CTS (единообразное и безопасное управление типами данных в программе); 4) многоступенчатая, гибкая систем обеспечения безопасности программного кода (в частности, на основе механизма сборок).
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Библиография (1) 1. 2. 3. 4. 5.
Hughes J. Why functional programming matters. The Computer Journal, 32 (2): 98-107, April 1989 Peyton Jones S.L., Lester D. Implementing of functional languages: A tutorial. International Series in Computeer Science - Prentice Hall, 1992 Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).- Prentice Hall, 2000 Milner R., Tofte M., Harper R., McQueen D. The definition of Standard ML: Revised 1997. MIT Press, 1997 Gilmore S. Programming in Standard ML ’97: a tutorial introduction. http:/www.dcs.ed.ac.uk/home/stg © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках одной лекции можно лишь в общих чертах охарактеризовать функциональный подход к программированию. Мы ограничились рассмотрением лишь наиболее существенных аспектов функционального подхода. Для более детального ознакомления с современными достижениями и проблемами в области проектирования и реализации языков функционального программирования, рекомендуется следующий список литературы: 1. Hughes J. Why functional programming matters. The Computer Journal, 32 (2): 98-107, April 1989 2. Peyton Jones S.L., Lester D. Implementing of functional languages: A tutorial. International Series in Computeer Science - Prentice Hall, 1992 3. Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).Prentice Hall, 2000 4. Milner R., Tofte M., Harper R., McQueen D. The definition of Standard ML: Revised 1997. MIT Press, 1997 5. Gilmore S. Programming in Standard ML ’97: a tutorial introduction. http:/www.dcs.ed.ac.uk/home/stg Кратко остановимся на источниках. В работах [1,2] обсуждаются основы функционального подхода к программированию. Работа [3] является энциклопедией языков программирования и рассматривает подходы в сравнительном и историческом аспектах. Работы [4,5] посвящены описанию языка программирования Standard ML и практике программирования на нем.
Современные языки программирования и .NET: I семестр Лекция 3: Функциональный подход к программированию
Библиография (2) 1. 2. 3. 4. 5.
http://www.haskell.org http://www.cm.bell-labs.com/cm/cs/what/smlnj http://www.harlequin.com/products/ads/ml http://www.cam.inria.fr http://www.cs.kun.nl/~clean
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Последние тенденции в развитии языков функционального программирования доступны из следующих Интернет-ресурсов: 1. http://www.haskell.org 2. http://www.cm.bell-labs.com/cm/cs/what/smlnj 3. http://www.harlequin.com/products/ads/ml 4. http://www.cam.inria.fr 5. http://www.cs.kun.nl/~clean Ресурс [1] описывает язык программирования Haskell, ресурсы [2-4] посвящены различным диалектам ML, ресурс [5] описывает один из современных функциональных языков – Clean.
Ламбда-исчисление как формализация языка функционального программирования
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к истории развития, идеологии, математическому основанию и обзору возможностей ламбда-исчисления – математической формализации, моделирующей языки функционального программирования.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Содержание лекции 1. 2. 3. 4. 5. 6.
Функция в математике и программировании Эволюция ламбда-исчисления Бестиповое ламбда-исчисление А. Черча: алфавит, аксиомы, правила вывода Преимущества ламбда-исчисления как формальной системы Ламбда-исчисление как формализация языка SML Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию ключевой сущности функционального подхода к программированию, а именно, функции. При этом будет особо отмечено то обстоятельство, что понятие функции различным образом интерпретируется в математической теории и в практике программирования. Далее будет представлено формальное введение в бестиповый вариант ламбдаисчисления, первоначально предложенный А. Черчем. Согласно традиции, изложение формальной теории будет вестись в следующей последовательности: алфавит, аксиомы и правила вывода. По результатам представленной теории будут сделаны выводы о преимуществах и недостатках ламбда-исчисления для моделирования конструкций языков функционального программирования. При этом существенное внимание будет уделено формализации языка функционального программирования SML, который изучается на протяжении всего курса. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Общие сведения о λ-исчислении Ламбда-исчисление – математическая теория, предназначенная для формализации обозначения и переобозначения как предмета программирования Классическая логика (и большинство других разделов математики) неудовлетворительны для решения данной проблемы Основной объект ламбда-исчисления – функция © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для формализации понятия «функция» была построена математическая теория, известная сегодня под названием ламбда-исчисления. Более точно это исчисление следует называть исчислением ламбда-конверсий. Под конверсией понимается преобразование объектов исчисления (а в программировании – функций и данных) из одной формы в другую. Исходной задачей в математике было стремление к упрощению формы выражений. В программировании именно эта задача не является столь существенной, хотя, как мы увидим в дальнейшем, использование ламбдаисчисления как исходной формализации может способствовать упрощению вида программы, т.е. вести к оптимизации программного кода. Кроме того, конверсии обеспечивают переход к вновь введенным обозначениям и, таким образом, позволяют представлять предметную область в более компактном или более детальном виде, или, говоря математическим языком, изменять уровень абстракции по отношению к предметной области. Эту возможность широко используют также языки объектно-ориентированного и структурно-модульного программирования в иерархии объектов, фрагментов программ и структур данных. На этом же принципе основано взаимодействие компонентов приложения в .NET. Именно в этом смысле переход к новым обозначениям является одним из важнейших элементов программирования в целом, и именно ламбда-исчисление (в отличие от многих других разделов математики), как оказывается, является адекватным способом формализации переобозначений. Поскольку основным объектом ламбда-исчисления является функция, этот подход является весьма продуктивным при моделировании языков функционального программирования.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Функция в математике и программировании Математической функцией f с областью определения A и областью значений B называется множество упорядоченных пар (a,b)∈A×B, таких что если (a,b1)∈f и (a,b2)∈f, то b1=b2. Функцией в языке программирования называется конструкция этого языка, описывающая правила преобразования аргумента (т.н. фактического параметра) в результат. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Заметим, однако, что под термином «функция» в математической формализации и программной реализации имеются в виду различные понятия. Так, математической функцией f с областью определения A и областью значений B называется множество упорядоченных пар (a,b) ∈ A×B, таких, что если (a,b1) ∈ f и (a,b2) ∈f, то b1=b2. В свою очередь, функцией в языке программирования называется конструкция этого языка, описывающая правила преобразования аргумента (так называемого фактического параметра) в результат.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
История развития ламбда-исчисления (1) 1924 – М. Шенфинкель (Moses Shönfinkel) разработал простую (simple) теорию функций 1934 – А. Черч (Alonso Church) предложил ламбда-исчисление и применил его для разработки теории множеств 1958 – Х. Карри (Haskel Curry) создал ламбда-исчисление для программирования без переменных – комбинаторную логику © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним ход эволюции теорий, лежащих в основе современного подхода к ламбдаисчислению. Еще в 1924 г. М. Шенфинкель (Moses Shönfinkel) разработал простую (simple) теорию функций, которая фактически являлась исчислением объектов-функций и предвосхитила появление ламбда-исчисления. Затем в 1934 г. А. Черч (Alonso Church) предложил собственно исчисление ламбдаконверсий или ламбда-исчисление и применил его для исследования теории множеств. Вклад ученого был настолько фундаментальным, что теория до сих пор называется ламбда-исчислением и часто именуется в литературе ламбда-исчислением Черча. Позднее, в 1940 г., Х. Карри (Haskell Curry) предложил теорию функций без переменных (иначе называемых комбинаторами), известную в настоящее время как комбинаторная логика. Эта теория является развитием ламбда-исчисления и представляет собой формальный язык, аналогичный языку функционального программирования и позволяющий более наглядно моделировать вычисления в среде абстрактных машин, в значительной мере схожих с виртуальной машиной .NET.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
История развития ламбда-исчисления (2) 1960-е – Р. Хиндли (Roger Hindley) исследовал типизацию в комбинаторной логике для моделирования языков функционального программирования со строгой типизацией 1960-е – П. Лендин (Peter Landin) использовал ламбдаисчисление для анализа языка ALGOL 60 1960-е – П. Лендин создал вычислительную модель в форме абстрактной машины SECD для моделирования языков со строгой типизацией, в частности ML © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Позднее, уже в 60-х г.г. Р. Хиндли (Roger Hindley) разработал выводимость типов (type inference), т.е. возможность неявно определить тип выражения, исходя из типов выражений, которые его окружают. Именно эта возможность широко используется в современных языках программирования, таких как SML и Haskell. Также в 60-х г.г. П. Лендин (Peter Landin) создал первую абстрактную машину на основе расширенного ламбда-исчисления. Машина получила название SECD и формализовала вычисления на языке программирования ISWIM (If you See What I Mean), который впоследствии стал прообразом языка функционального программирования ML. Наконец, в 70-х г.г. Р. Милнер (Robin Milner) создал полиморфную систему типизации для языка функционального программирования ML, которая вместе с развернутым описанием того же автора положила начало стандартизации этого языка программирования. Язык ML, составляющий ядро более позднего языка SML, в полной мере формализуется посредством ламбда-исчисления.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
История развития ламбда-исчисления (3) 1970-е – П. Кюрьен (Piere Curien) и др. создали категориальную абстрактную машину, на основе которой был реализован CaML, один из современных диалектов ML 1970-е – К. Уодсворт (Christopher Wadsworth) предложил механизм редукции графов для моделирования «ленивых» вычислений в ламбда-исчислении 1970-е Д. Тернер (David Turner) предложил аналогичный механизм для «ленивых» вычислений в комбинаторах © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Уже в 70-е г.г. группой ученых института INRIA (Франция), ведущую роль в работе которой сыграл Пьер Кюрьен, была создана еще одна абстрактная машина, основанная на смене состояний и получившая название категориальной абстрактной машины, или, сокращенно, КАМ. Теория категорий в форме категориальной комбинаторной логики, которая является теоретическим фундаментом для КАМ, по сути, представляет собой вариант ламбда-исчисления. С помощью КАМ был реализован еще один современный диалект ML, получивший название CaML (по имени машины). В 70-х г.г. произошли произошли еще два значительных события в истории ламбдаисчисления. К. Уодсвортом и Д. Тернером были предложены механизмы оптимизации вычислений посредством редукции графов, причем оба механизма существенно использовали ламбда-исчисление (первый – в чистом виде, а второй – в форме комбинаторной логики). Таким образом, практически все ранее созданные формализации языков функционального программирования (включая абстрактные машины и средства оптимизации вычислений) базируются на фундаменте ламбда-исчисления в той или иной его форме.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Ламбда-исчисление: основные компоненты Алфавит – множество допустимых символов Утверждения – правила образования терминальных символов Аксиомы – элементарные утверждения, истинность которых принимается без доказательства Правила вывода – правила преобразования одних символов (объектов) языка в другие © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перейдем к описанию ламбда-исчисления как формальной системы. Согласно математической практике, необходимо определить следующие элементы теории: • алфавит; • утверждения; • аксиомы; • правила вывода. При этом под алфавитом понимается множество символов, допустимых в нотации той или иной формализации. Утверждения устанавливают математической теории.
правила
образования
терминальных
символов
Под аксиомами понимаются элементарные утверждения, которые считаются истинными без необходимости доказательства истинности. Правила вывода определяют правила преобразования одних символов (объектов), исследуемых в теории, в другие объекты.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Ламбда-исчисление: алфавит Константы: c1, c2, … - малые буквы латинского алфавита, возможно, с индексами Переменные: x, y, … - малые буквы латинского алфавита, возможно, с индексами Выражения (термы): M, N, … - заглавные буквы латинского алфавита, возможно, с индексами Специальные символы: “(“, “)”, “.”
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим алфавит ламбда-исчисления. Допускаются элементы четырех видов: 1) константы; 2) переменные; 3) выражения (или, иначе, термы); 4) специальные символы. При этом принимаются следующие обозначения. Константы c1, c2, … обозначаются малыми буквами латинского алфавита, возможно, с индексами. Переменные x, y, … обозначаются малыми буквами латинского алфавита, возможно, с индексами. Выражения (или, иначе, термы) M, N, … обозначаются заглавными буквами латинского алфавита, возможно, с индексами. Допускается использование следующих специальных символов (взяты в кавычки и разделены запятыми): “(“, “)”, “.”
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Ламбда-исчисление: построение термов Термы определяются индукцией по построению. Все переменные и константы являются термами. Для любых термов M, N и переменной x верно, что 1) (λx.M) – терм; 2) (MN) – терм. При этом выражение (MN) обозначает операцию аппликации (применения функции к аргументу), а (λx.M) – абстракции. Никакой другой набор символов не является термом. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим далее порядок конструирования допустимых для заданного алфавита ламбдавыражений, или, иначе, термов. Ламбда-термы строятся по индукции (порядок построения можно считать определением) следующим образом. Базис индукции: любая переменная или константа является ламбда-термом по определению. Шаг индукции: если M, N – произвольные ламбда-термы и x –произвольная переменная, то справедливо, что: • во-первых, выражение (λx.M) является допустимым ламбда-термом; • во-вторых, выражение (MN) является допустимым ламбда-термом. Заметим, что при этом ламбда-выражение (MN) обозначает операцию аппликации (или применения функции к аргументу), а ламбда-выражение (λx.M) – операцию абстракции. Кроме того, примем, что никакой другой набор символов не является допустимым ламбда-термом.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Ламбда-исчисление: аксиомы Следующие аксиомы задают свойства отношения конвертируемости (приводимости одного терма к другому), обозначаемого символом “=”. (α) λx.a = λz.[z/x]a; (β) (λx.a)b = [b/x]a. Аксиома (α) означает возможность подстановки терма z вместо всех вхождений переменной x в терм а. Аксиома (β) означает возможность редукции (упрощения вида) терма в левой части путем подстановки b вместо всех вхождений переменной x в терм а. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду После определения алфавита и порядка построения допустимых ламбда-выражений посредством операций аппликации и абстракции, перечислим аксиомы ламбдаисчисления. Отметим, что употребляемый ниже символ “=” понимается в ламбда-исчислении как обозначение отношения конвертируемости, которым связываются соединенные этим значком ламбда-выражения. Конвертируемость двух ламбда-выражений означает, что одно ламбда-выражение может быть преобразовано к другому. Отношение конвертируемости моделирует переобозначения и во многих отношениях, как уже отмечалось, напоминает процесс программирования. Следующие аксиомы задают свойства отношения конвертируемости: (α) λx.a = λz.[z/x]a; (β) (λx.a)b = [b/x]a. Аксиома (α) означает возможность подстановки терма z вместо всех вхождений переменной x в ламбда-выражение а. Аксиома (β) означает возможность редукции (то есть упрощения вида) ламбда-выражения в левой части путем подстановки b вместо всех вхождений переменной x в ламбдавыражение а. Фактически редукция означает возможность создания (в ламбда-исчислении или на языке программирования) одной функции (ламбда-выражения) как сокращенной записи другой функции (ламбда-выражения).
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Ламбда-исчисление: правила вывода Следующие правила вывода термов задают свойства отношения конвертируемости: (μ) если a=b, то ca=cb; (ν) если a=b, то ac=bc; (ξ) если a=b, то λx.a= λx.b; (ρ) a=a (рефлексивность); (σ) если a=b, то b=a (симметричность); (τ) если a=b и b=c, то a=c (транзитивность).
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перечислим правила вывода термов, которые задают характеристики отношения конвертируемости: (μ) если a=b, то ca=cb; (ν) если a=b, то ac=bc; (ξ) если a=b, то λx.a= λx.b; (ρ) a=a (рефлексивность); (σ) если a=b, то b=a (симметричность); (τ) если a=b и b=c, то a=c (транзитивность). Как видно из перечисленных выше свойств, отношение конвертируемости обладает, в частности, свойствами рефлексивности, симметричности и транзитивности. Первое из только что перечисленных свойств означает конвертируемость произвольного ламбдавыражения к самому себе, второе – двунаправленность вывода ламбда-выражений конвертированием, а третье – возможность опускать промежуточные этапы конверсии для цепочек вывода. Именно в силу фундаментальности отношения конвертируемости для ламбда-исчисления эта теория известна также под другим, более точно характеризующим ее суть названием, а именно, как исчисление ламбда-конверсий.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Соглашения об обозначениях •
скобки для операции аппликации восстанавливаются по ассоциации влево: x y = (x y), x y z = ((x y) z), …
•
избыточные скобки могут опускаться: (x y) = x y, ((x y) z) = x y z, …
•
скобки для операции абстракции восстанавливаются по ассоциации вправо: λxy.M = (λx.(λy.M)), λxyz.M = (λx.(λy. (λz.M))), … © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, относительная простота описания предыдущих этапов формальной теории ламбда-конверсий (алфавита, аксиом и правил вывода) порождает довольно громоздкие выкладки при моделировании вычислений. В этой связи из соображения экономии пространства для вывода соотношений принимаются следующие умолчания, позволяющие значительно сократить запись и увеличить удобство прочтения и обработки ламбда-выражений. Во-первых, скобки для операции аппликации восстанавливаются по ассоциации влево, например: x y = (x y), x y z = ((x y) z), … Во-вторых, избыточные скобки могут опускаться, например: (x y) = x y, ((x y) z) = x y z, … В-третьих, скобки для операции абстракции восстанавливаются по ассоциации вправо, например: λxy.M = (λx.(λy.M)), λxyz.M = (λx.( λy. (λz.M))), …
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Примеры ламбда-термов 1)
x (переменная);
2)
1 (константа);
3)
λx.x (функция тождества);
4)
λx.x + 1 (функция инкремента – прибавления единицы);
5)
( λx.x + 1)2 = [2/x](λx.x + 1) = 2+1 = 3 (вычисление значения функции);
6)
a $ b (недопустимый ламбда-терм). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем формальное описание исчисления ламбда-конверсий необходимыми содержательными примерами. Рассмотрим следующие шесть ламбда-термов, возможно, с цепочками вывода: 1) x; 2) 1; 3) λx.x; 4) λx.x + 1; 5) (λx.x + 1)2 = [2/x]( λx.x + 1) = 2+1 = 3; 6) a $ b. Согласно правилам построения алфавита, первый из ламбда-термов является переменной, а второй – константой. Третий ламбда-терм, согласно правилам построения выражений, представляет собой ламбда-абстракцию переменного терма x к самому себе, т.е. определяет функцию тождества. Четвертый ламбда-терм отличается от третьего тем, что добавляет к аргументу x константу 1, т.е. определяет функцию инкремента (или прибавления единицы). Заметим, что в алфавите ламбда-исчисления отсутствует функция сложения как таковая, так что возможны различные интрепретации символа «+» (будем считать его далее «встроенной» функцией сложения). Пятый ламбда-терм обозначает подстановку согласно аксиоме (α) константы 2 вместо всех вхождений x в выражение x+1 (вычисление значения функции в число 3 возможно при корректной интерпретации символа «+»). Шестой ламбда-терм недопустим из-за вхождения неопределенного символа «$».
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Примеры элементарных программ на SML (1) 1)
x (переменная, тип определяется в процессе трансляции);
2)
1 (константа);
3)
fn x => x (функция тождества);
4)
fn x => x+1 (функция инкремента);
5)
(fn x => x+1) 2 (вычисление значения функции, в результате выполнения получается 3)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем соответствие между математической моделью языка функционального программирования – ламбда-исчислением и языком функционального программирования SML. Несмотря на то, что мы еще не изучали синтаксис языка, соответствие между ламбдаисчислением и функциональным языком настолько естественно, что сопоставление ламбда-термов SML-выражениям происходит практически интуитивно и не нуждается в дальнейших комментариях. Приведем фрагменты SML-программ, соответствующих допустимым ламбда-термам из предыдущего слайда: 1) 2) 3) 4) 5)
x (переменная, тип которой определяется в процессе трансляции на этапе контроля типизации в соответствии с выводом типов); 1 (константа); fn x => x (функция тождества); fn x => x+1 (функция инкремента); (fn x => x+1) 2 (вычисление значения функции, в результате выполнения получается целое число 3).
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Примеры элементарных функций на SML (2) Функция f с формальным параметром x и телом b задается следующим описанием: fun f x = b, например, fun f x = 1+x; Для вычисления значения выражения необходимо произвести аппликацию функции к данному выражению: f 4; При вычислении значения функции аппликация производится к ближайшему аргументу: f 2 + 3; означает (f 2)+3, а не f(2+3). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим иллюстрацию соответствия между программами на языке SML и ламбдавыражениями, исследовав операцию аппликации функции к аргументу. Рассмотрим описание функции инкремента с предыдущего слайда: fun f x = 1+x; Здесь нужно учитывать, что в общем случае функция f языка программирования SML, имеющая формальный параметр x и тело b, задается следующим описанием: fun f
x = b;
Для вычисления значения выражения необходимо произвести аппликацию функции к данному выражению, для аппликации функции f к целому числу 4 нужно записать: f
4;
При вычислении значения функции аппликация производится к ближайшему аргументу. Так, запись f 2 + 3; означает порядок аппликации (f 2)+3, а не f(2+3), т.е. находится в полном соответствии с соглашениями о скобках, принятыми в ламбда-исчислении.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Преимущества ламбда-исчисления 1. 2. 3. 4. 5.
Лаконичность (небольшое количество аксиом и правил вывода) Интуитивная ясность Иллюстративность (прозрачность графической интерпретации) Полнота (представимость произвольной функции) Естественная близость к языкам функционального программирования (SML, Scheme, Haskell, Miranda, Hope, Clean) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрев формальное построение исчисления ламбда-конверсий (алфавит, аксиомы и правила вывода выражений) и сопоставив основные элементы (переменная, константа) и операции (аппликация, подстановка) этой теории с базовыми элементами (переменная, константа) и элементарными программами (объявление и аппликация функции) языка SML, можно сделать вывод о следующих несомненных преимуществах ламбдаисчисления как математической модели языка функционального программирования: 2)
лаконичность (ограниченный необходимыми элементами алфавит, два способа построения выражений – аппликация и абстракция, небольшое количество аксиом и правил вывода);
3)
интуитивная ясность (обозначения являются краткими и легко доступны для понимания);
4)
иллюстративность (ламбда-термы легко интерпретируются не только с помощью алгебраической записи, но и посредством визуальной интерпретации в виде графов, причем редукция, т.е. упрощение вида графов соответствует бета-редукции ламбда-термов);
5)
полнота (в ламбда-исчислении возможно представить произвольную, в частности, сколь угодно сложную, функцию);
6)
естественная близость к языкам функционального программирования (SML, Scheme, Haskell, Miranda, Hope, Clean) была проиллюстрирована на примере SML на двух предыдущих слайдах.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Библиография (1) 1. 2.
3. 4.
Barendregt H.P. The lambda calculus (revised edition), Studies in Logic, 103, North Holland, Amsterdam, 1984 Schönfinkel M. ‘Über die Bausteine der matematischen Logik, Math. Annalen 92, pp. 305-316, 1924. Translation printed as ‘On the building blocks of mathematical logic’, in van Heijenoort, J. (ed.), From Frege to Gödel, Harvard University Press, 1967 Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 Hindley J.R., Seldin J.P. Introduction to combinators and λcalculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать такую многоаспектную и гибкую теорию, как исчисление ламбда-конверсий. Мы ограничились рассмотрением лишь наиболее существенных аспектов этой формализации языков функционального программирования. Для более детального ознакомления с особенностями, достижениями и проблемами в области ламбда-исчисления рекомендуется следующий список литературы: 1. Barendregt H.P. The lambda calculus (revised edition), Studies in Logic, 103, North Holland, Amsterdam, 1984 2. Schönfinkel M. ‘Über die Bausteine der matematischen Logik, Math. Annalen 92, pp. 305316, 1924. Translation printed as ‘On the building blocks of mathematical logic’, in van Heijenoort, J. (ed.), From Frege to Gödel, Harvard University Press, 1967 3. Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 4. Hindley J.R., Seldin J.P. Introduction to combinators and l-calculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986 Кратко остановимся на источниках. Работа [1] является энциклопедией ламбдаисчисления. Работа [2] содержит обсуждение так называемых простых (simple) функций и предваряет появление ламбда-исчисления. Работы [3,4] посвящены расширению ламбдаисчисления – комбинаторной логике.
Современные языки программирования и .NET: I семестр Лекция 4: Ламбда-исчисление как формализация ЯФП
Библиография (2) 1. 2. 3. 4. 5.
Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 Gordon M.J.C. Progaramming language theory and its implementation. Prentice-Hall, 1988 Hughes J. Why functional programming matters. The Computer Journal, 32(2)98-107, April 1989 Hindley J.R. The principal type-scheme of an object in combinatory logic. Trans. Amer. Math. Soc., 146:29-60, 1969 Milner R., Tofte M., Harper R., McQueen D. The definition of Standard ML (Revised 1997). The MIT Press, 1997 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение библиографии. Работы [1-3] посвящены вопросам реализации языков программирования, в частности, на основе функционального подхода. Работа [4] содержит обсуждение типизации в комбинаторной логике, как мы увидим впоследствии, адекватно моделирующей типизацию языка SML. Работа [5] посвящена описанию синтаксиса и возможностей языка SML.
Комбинаторная логика как формальная система
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к истории развития, идеологии, математическому основанию и обзору возможностей комбинаторной логики – математической формализации, моделирующей языки функционального программирования и абстрактные вычислительные машины.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Содержание лекции 1. 2. 3. 4. 5. 6. 7.
Определение комбинатора Комбинаторная логика как формальная система: алфавит, аксиомы, правила вывода Примеры комбинаторов Определение базиса. Основные базисы комбинаторной логики Приписывание типов комбинаторам. Выводимость типов Примеры функций базисных комбинаторов на SML Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию ключевой сущности функционального подхода к программированию, а именно, функции. При этом будет особо отмечено то обстоятельство, что (типизированные) функции языков программирования естественным и интуитивно понятным образом моделируются посредством комбинаторов – ламбда-выражений специального вида (с приписанными им типами). Далее будет представлено формальное введение в типизированный вариант комбинаторной логики, первоначально предложенный Х. Карри. Изложение формальной теории будет производиться в традиционной для математики последовательности: алфавит, аксиомы и правила вывода. Затем будет обсуждаться понятие базисного набора комбинаторов: будут рассмотрены несколько вариантов базисов, включая минимально возможный. По результатам представленной теории будут сделаны выводы о преимуществах и недостатках комбинаторной логики для моделирования конструкций языков функционального программирования со строгой типизацией. При этом существенное внимание будет уделено формализации языка функционального программирования SML, который изучается на протяжении всего курса, в частности, вопросу выводимости типов. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Важнейшие работы в комбинаторной логике 1920-е – М. Шенфинкель (Moses Shönfinkel) разработал формальную систему, основанную на объектах, подобных комбинаторам 1950-е – Х. Карри (Haskell B. Curry) создал комбинаторную логику как формальную систему 1960-е – Д. Тернер (David Turner) предложил использовать комбинаторы в качестве низкоуровневого кода для трансляторов языков функционального программирования 1960-е – П. Лендин (Peter Landin) создал абстрактную машину на состояниях, основанную на комбинаторном подходе © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним ход эволюции теорий, лежащих в основе современного подхода к ламбдаисчислению. Еще в 1924 году М. Шенфинкель (Moses Shönfinkel) разработал простую (simple) теорию функций, которая фактически являлась исчислением объектов-функций и предвосхитила появление ламбда-исчисления, а затем и комбинаторной логики. Позднее, в 50-х г.г., Х. Карри (Haskell Curry) предложил теорию функций без переменных (иначе называемых комбинаторами), известную в настоящее время как комбинаторная логика. Эта теория представляет собой формальный язык, аналогичный языку функционального программирования и позволяющий моделировать вычисления в среде абстрактных машин, в значительной мере схожих с виртуальной машиной .NET. В 60-х г.г. Д. Тернер (David Turner) предложил использовать комбинаторы в качестве низкоуровневого кода для трансляторов языков функционального программирования, т.е. предвосхитил появление абстрактных машин, использующих в качестве инструкций комбинаторы. Затем, уже в 60-х г.г. П. Лендин (Peter Landin) создал первую абстрактную машину на основе комбинаторной логики. Машина получила название SECD и формализовала вычисления на языке программирования ISWIM (If you See What I Mean), который впоследствии стал прообразом языка функционального программирования ML. Основным понятием для SECD-машины является понятие состояния. Уже в 70-е г.г. группой ученых института INRIA (Франция) была создана абстрактная машина, основанная на смене состояний и получившая название категориальной абстрактной машины, или, сокращенно, КАМ. КАМ основана на теории категорий в форме категориальной комбинаторной логики. С помощью КАМ был реализован еще один современный диалект ML, получивший название CaML.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Определение комбинатора Переменная x называется свободной в терме λx.A, если она не имеет вхождений в терм A; в противном случае переменная x называется связанной Для составных термов связанность переменных определяется индукцией по построению. Терм, не содержащий свободных переменных, называется комбинатором. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Важнейшим понятием для любой формы комбинаторной логики является понятие комбинатора. Для того, чтобы формально определить комбинатор, необходимо ввести понятие свободной и связанной переменной в ламбда-выражении. Переменная x называется свободной в ламбда-выражении (терме) вида λx.A, если она не имеет вхождений в терм A; в противном случае переменная x называется связанной. Для составных ламбда-выражений понятие связанной и свободной переменной определяется индукцией по построению с учетом возможных способов комбинирования, а именно, операций аппликации и абстракции. Теперь становится возможным дать лаконичное определение комбинатора. Ламбда-выражение комбинатором.
(терм),
не
содержащее
свободных
переменных,
называется
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Комбинаторная логика: основные компоненты Алфавит – множество допустимых символов Утверждения – правила образования терминальных символов Аксиомы – элементарные утверждения, истинность которых принимается без доказательства Правила вывода – правила преобразования одних символов (объектов) языка в другие
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перейдем к описанию комбинаторной логики как формальной системы. Согласно математической практике, необходимо определить следующие элементы теории: • алфавит; • утверждения; • аксиомы; • правила вывода. Напомним, что под алфавитом понимается множество символов, допустимых в нотации той или иной формализации. Утверждения устанавливают математической теории.
правила
образования
терминальных
символов
Под аксиомами понимаются элементарные утверждения, которые считаются истинными без необходимости доказательства истинности. Правила вывода определяют правила преобразования одних символов (объектов), исследуемых в теории, в другие объекты.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Комбинаторная логика: алфавит Константы: c1, c2, … - малые буквы латинского алфавита, возможно, с индексами Переменные: x, y, … - малые буквы латинского алфавита, возможно, с индексами Выражения (термы): M, N, … - заглавные буквы латинского алфавита, возможно, с индексами Специальные символы: “(“, “)”
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим алфавит комбинаторной логики. Допускаются элементы четырех видов: 1) константы; 2) переменные; 3) комбинаторные выражения (или, иначе, термы); 4) специальные символы. При этом принимаются следующие обозначения. Константы c1, c2, … обозначаются малыми буквами латинского алфавита, возможно, с индексами. Переменные x, y, … обозначаются малыми буквами латинского алфавита, возможно, с индексами. Выражения (или, иначе, термы) M, N, … обозначаются заглавными буквами латинского алфавита, возможно, с индексами. Допускается использование следующих специальных символов (взяты в кавычки и разделены запятыми): “(“, “)”.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Комбинаторная логика : построение термов Термы определяются индукцией по построению. Все переменные и константы являются термами. Для любых термов M, N и переменной x верно, что (MN) – терм. При этом выражение (MN) обозначает операцию аппликации (применения функции к аргументу) Операции абстракции в комбинаторной логике не существует. Никакой другой набор символов не является термом. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим далее порядок конструирования допустимых для заданного алфавита комбинаторных выражений, или, иначе, термов. Комбинаторные термы строятся по индукции (порядок построения можно считать определением) следующим образом. Базис индукции: любая переменная или константа является комбинаторным термом по определению. Шаг индукции: если M, N – произвольные комбинаторные термы и x – произвольная переменная, то справедливо, что: • выражение (MN) является допустимым комбинаторным термом. Заметим, что при этом комбинаторное выражение (MN) обозначает операцию аппликации (или применения функции к аргументу). Кроме того, примем, что никакой другой набор символов не является допустимым комбинаторным термом.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Комбинаторная логика: аксиомы Следующие аксиомы задают свойства отношения конвертируемости (приводимости одного терма к другому), обозначаемого символом “=”. (I) Ix = x; (K) Kxy = x; (S) Sxyz = xz(yz). Аксиома (I) соответствует функции тождества. Аксиома (K) соответствует функции взятия первой проекции. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду После определения алфавита и порядка построения допустимых комбинаторных выражений посредством операции аппликации, перечислим аксиомы комбинаторной логики. Отметим, что употребляемый ниже символ “=” понимается в комбинаторной логике как обозначение отношения конвертируемости, которым связываются соединенные этим значком комбинаторные термы. Конвертируемость двух комбинаторных термов означает, что один комбинаторный терм может быть преобразован к другому. Отношение конвертируемости моделирует переобозначения и во многих отношениях, как отмечалось ранее, напоминает процесс программирования. Следующие аксиомы задают свойства отношения конвертируемости: (I) Ix = x; (K) Kxy = x; (S) Sxyz = xz(yz). Аксиома (I) означает существование комбинатора (функции) тождества, т.е. наличие тождественного преобразования, при котором любой аргумент отображается сам в себя. Аксиома (K) означает существование комбинатора (функции) взятия первой проекции, т.е. первого элемента упорядоченной пары или первого элемента списка. Интуитивно ясно, что эта аксиома близка языкам функционального программирования, оперирующим списками, и соответствует фундаментальной операции взятия головного (первого) элемента списка.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Комбинаторная логика: правила вывода Следующие правила вывода термов задают свойства отношения конвертируемости: (μ) если a=b, то ca=cb; (ν) если a=b, то ac=bc; (ρ) a=a (рефлексивность); (σ) если a=b, то b=a (симметричность); (τ) если a=b и b=c, то a=c (транзитивность).
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перечислим правила вывода комбинаторных термов, которые задают характеристики отношения конвертируемости: (μ) если a=b, то ca=cb; (ν) если a=b, то ac=bc; (ρ) a=a (рефлексивность); (σ) если a=b, то b=a (симметричность); (τ) если a=b и b=c, то a=c (транзитивность). Как видно из перечисленных выше свойств, отношение конвертируемости обладает, в частности, свойствами рефлексивности, симметричности и транзитивности. Первое из только что перечисленных свойств означает конвертируемость произвольного комбинаторного выражения к самому себе, второе – двунаправленность вывода комбинаторных выражений посредством конверсии, а третье – возможность опускать промежуточные этапы конверсии для цепочек вывода.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Соглашения об обозначениях •
скобки для операции аппликации восстанавливаются по ассоциации влево: X Y = (X Y), X Y Z = ((X Y) Z), …
•
избыточные скобки могут опускаться: (X Y) = X Y, ((X Y) Z) = X Y Z, …
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, относительная простота описания предыдущих этапов формальной теории комбинаторной логики (алфавита, аксиом и правил вывода) порождает довольно громоздкие выкладки при моделировании вычислений. В этой связи из соображения экономии пространства для вывода соотношений принимаются следующие умолчания, позволяющие значительно сократить запись и увеличить удобство прочтения и обработки комбинаторных термов. Во-первых, скобки для операции аппликации восстанавливаются по ассоциации влево, например: X Y = (X Y), X Y Z = ((X Y) Z), … Во-вторых, избыточные скобки могут опускаться, например: (X Y) = X Y, ((X Y) Z) = X Y Z, …
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Синтаксис комбинаторной логики БНФ-описание комбинатора имеет вид: <комбинатор> ::= K | S | (<комбинатор> <комбинатор>) БНФ-описание терма комбинаторной логики, возможно, содержащего переменные, имеет вид: <комбинаторный терм> ::= K|S| <переменная> | (<комбинаторный терм> <комбинаторный терм>) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Под синтаксисом понимают это раздел описания формального математического языка или языка программирования, исследующий вид, форму и структуру конструкций, без учета их значения (или, иначе, семантики) или практической применимости (или, иначе, прагматики). Задать синтаксис языка возможно, перечислив описание его конструкций, например, с помощью форм Бэкуса-Наура или БНФ. БНФ созданы в 60-х г.г. Дж. Бэкусом (John Backus) и развиты П. Науром (Peter Naur) как метаязык для формализации синтаксиса языка программирования ALGOL 60. Впоследствии БНФ получили широкое распространение и в настоящее время являются основной нотацией для формализации синтаксиса языков программирования (мы будем пользоваться БНФ для формализации синтаксиса языка программирования SML). В данной нотации символ «::=» интерпретируется словами «может иметь вид», а символ «|» – словом «или». Определяемое и определяющие понятия записываются в угловых скобках, первое – слева, а последние – справа от значка «::=». Формализуем синтаксис выражений комбинаторной логики (или комбинаторов). БНФ-описание комбинатора имеет вид: <комбинатор> ::= K | S | (<комбинатор> <комбинатор>) БНФ-описание терма комбинаторной логики, возможно, содержащего переменные, имеет вид: <комбинаторный терм> ::= K|S| <переменная> | (<комбинаторный терм> <комбинаторный терм>)
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Примеры комбинаторов I a = a (комбинатор тождества) К ab = a (комбинатор-канцелятор, первая проекция) S abc = ac(bc) (комбинатор-коннектор, связывание) B abc = a(bc) (комбинатор композиции) C abc = acb (комбинатор-пермутатор, перестановка) W xy = xyy (комбинатор-дупликатор, дублирование)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем представленную формальную систему комбинаторной логики необходимыми примерами комбинаторов. Рассмотрим характеристические соотношения для комбинаторов, которые впоследствии окажутся теоретически интересными и практически полезными в данном курсе (некоторые из соотношений совпадают с введенными ранее аксиомами): (I) (K) (S) (B) (C) (W)
I a = a; К ab = a; S abc = ac(bc); B abc = a(bc); C abc = acb; W xy = xyy.
Соотношение (I), как уже отмечалось, характеризует комбинатор тождества. Соотношение (K), как уже отмечалось, характеризует комбинатор первой проекции (иначе именуемый канцелятором, т.е. «отменяющим» «выполнение» всех «инструкций», кроме первой). Соотношение (S) характеризует комбинатор-коннектор, который определяет порядок «связывания» «инструкций» программы таким образом, что третья «инструкция» «распределяется» по паре из двух первых. Соотношение (B) характеризует комбинатор композиции, который образует последовательность комбинаторных термов и служит для объединения более элементарных «инструкций» в более сложные, а в итоге – в «программы». Соотношения (C) и (W) определяют соответственно пермутацию (перестановку) и дублирование аргументов.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Редукция комбинаторов Редукция (преобразование для сокращения записи) комбинаторных термов возможна в соответствии с правилами вывода, аналогичным аксиомам (K) и (S). Пример. Рассмотрим комбинаторный терм S K K x. SKK x = K x (K x) = x.
(по правилу S) (по правилу K)
Ответ: S K K x = x, откуда, с учетом аксиом и правила (I), I = SKK. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним, что одной из основных причин возникновения ламбда-исчисления была необходимость исследовать возможность кратчайшей перезаписи выражения (функции) с сохранением эквивалентного значения. Для реализации этой возможности вводилось преобразование редукции ламбда-термов. Оказывается, что в комбинаторной логике наследуется возможность редукции. Поскольку она интересна теоретически (для сокращения выкладок) и полезна практически (для оптимизации программного кода абстрактных) машин, рассмотрим ее более подробно. В ходе исследований было выяснено, что редукция (преобразование для сокращения записи) комбинаторных термов возможна в соответствии с правилами вывода, аналогичными аксиомам (K) и (S). Проиллюстрируем моделирование механизма редукции следующим примером. Рассмотрим комбинаторный терм вида S K K x. Пользуясь аксиомами (К) и (S), а также правилами вывода, произведем редукцию терма: SKK x = K x (K x) = x.
(по правилу S) (по правилу K)
В результате получаем, что S K K x = x, откуда, с учетом аксиом и правила (I), I = SKK.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Базисы комбинаторов Множество (минимальной мощности) комбинаторов, через элементы которого выразим произвольный комбинатор, называется (минимальным) базисом. Минимальный базис: {K,S}. Другие примеры базисов: {I,K,S}; {I,B,C,S}; {B,W,K}. Примеры. Разложение термов в базисе {K,S}: B = S(KS)K; W = SS(K(SKK)); C = S(BBS)(KK). Разложение в базисе – аналог программирования. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как видно из предыдущего примера, одни комбинаторы можно выразить через другие. Возникает вопрос: существует ли некоторый конечный набор комбинаторов, посредством которого возможно выразить произвольный терм комбинаторной логики? Оказывается, что ответ на поставленный вопрос утвердительный, причем введенные аксиомы и правила вывода обеспечивают весьма лаконичный набор такого рода. Необходимость продолжения рассуждений приводит нас к понятию базиса. Множество (минимальной мощности) комбинаторов, через элементы которого выразим произвольный комбинатор, называется (минимальным) базисом. Как оказывается, можно доказать, что: 1) базис термов для комбинаторной логики действительно существует (причем существует бесконечное множество возможных базисов); 2) для любого базиса справедливо, что он обеспечивает представление произвольного комбинаторного терма (в силу свойства полноты, которым обладает система комбинаторной логики); 3) минимальный базис состоит всего из двух «инструкций»-комбинаторов, например, {K,S}. Приведем еще несколько примеров базисов: {I,K,S}; {I,B,C,S}; {B,W,K}. Разложение термов в базисе {K,S} для ранее рассмотренных комбинаторов имеет вид: B = S(KS)K; W = SS(K(SKK)); C = S(BBS)(KK). Разложение в базисе аналогично программированию на языке базисных инструкций.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Выводимость типов комбинаторов Тип a приписан комбинатору X тогда и только тогда, когда это утверждение получено из следующих аксиом (FI) |— #(I) = (a, a), (FK) |— #(K) = (a, (b,a)) = (a, b, a), (FS) |— #(S) = ((a, (b, c)), ((a, b)(a, c))) и правила вывода (F) если |— #(X) = (a, b) и |— #(U) = a, то |— #(XU) = b. Процедура контроля соответствия типов транслятора языка программирования работает аналогичным образом. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Оказывается, что комбинаторная логика обладает возможностью не только моделировать процесс реализации программного обеспечения на языке функционального программирования, но и прозрачно формализовать процедуру приписывания типов объектам этого языка. Под типом (или, иначе, сортом) будем понимать относительно устойчивую и независимую совокупность элементов, которую можно выделить во всем рассматриваемом множестве (предметной области). Более подробно типизация языков программирования и теория типов будут рассмотрены нами в ходе следующей лекции. В случае комбинаторной логики будем считать, что тип a приписан комбинатору X тогда и только тогда, когда это утверждение получено из следующих аксиом (FI) (FK) (FS)
|— #(I) = (a, a), |— #(K) = (a, (b,a)) = (a, b, a), |— #(S) = ((a, (b, c)), ((a, b)(a, c)))
и правила вывода (F)
если |— #(X) = (a, b) и |— #(U) = a, то |— #(XU) = b.
Заметим, что процедура контроля соответствия типов транслятора языка программирования реализована сходным образом, причем в ней существенно используется механизм сопоставления с образцом. В языке программирования SML, кроме того, применятся механизм получения логического вывода о типе выражения, исходя из контекста его использования. Этот механизм, известный также как выводимость типов (type inference), адекватно моделируется в терминах комбинаторной логики.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Реализация основных комбинаторов на SML Приведем функции для базисных комбинаторов: fun I x = x;
(комбинатор тождества)
fun K x y = x;
(комбинатор-канцелятор)
fun S x y z = x z (y z); (комбинатор-коннектор) Произвольный терм комбинаторной логики выразим через приведенные базисные комбинаторы. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В качестве иллюстрации естественности применения формальной системы комбинаторной логики для моделирования языка функционального программирования SML, приведем определения функций, реализующих характеристики некоторых из базисных комбинаторов: fun I x = x; fun K x y = x; fun S x y z = x z (y z); Реализация функций достаточно прозрачна и не требует пояснений. Заметим лишь, что функция I реализует комбинатор тождества I, функция K комбинатор-канцелятор K, а функция S – комбинатор-коннектор S.
–
Заметим в заключение, что произвольный терм комбинаторной логики выразим через приведенные базисные комбинаторы.
Современные языки программирования и .NET: I семестр Лекция 5: Комбинаторная логика как формальная система
Библиография 1. 2. 3. 4. 5.
Schönfinkel M. ‘Über die Bausteine der matematischen Logik, Math. Annalen 92, pp. 305-316, 1924. Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 Hindley J.R., Seldin J.P. Introduction to combinators and λcalculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986 Hindley J.R. The principal type-scheme of an object in combinatory logic. Trans. Amer. Math. Soc., 146:29-60, 1969 Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать такую многоаспектную и гибкую теорию, как формальная система комбинаторной логики. Мы ограничились рассмотрением лишь наиболее существенных аспектов этой формализации языков функционального программирования, включая краткое знакомство с приписыванием типа и выводимостью типов. Для более детального ознакомления с особенностями, достижениями и проблемами в области комбинаторной логики рекомендуется следующий список литературы: 1. Schönfinkel M. ‘Über die Bausteine der matematischen Logik, Math. Annalen 92, pp. 305316, 1924. 2. Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 3. Hindley J.R., Seldin J.P. Introduction to combinators and l-calculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986 4. Hindley J.R. The principal type-scheme of an object in combinatory logic. Trans. Amer. Math. Soc., 146:29-60, 1969 5. Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 Кратко остановимся на источниках. Работа [1] содержит обсуждение так называемых простых (simple) функций и предваряет появление комбинаторной логики. Работа [2] является энциклопедией формальной системы комбинаторной логики. Работа [3] связывает ламбда-исчисление и комбинаторную логику. Работа [4] описывает систему типизации комбинаторной логики. Работа [5] посвящена применению комбинаторов для практической реализации языков функционального программирования.
Теория типов и комбинаторная логика
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к истории развития, идеологии, математическому основанию и обзору возможностей типизированной комбинаторной логики и теории типов – математической формализации, моделирующей типы выражений в языках программирования.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8.
Понятие типа в математике и программировании Комбинатор как функциональный объект программы Приписывание типа комбинатору и функции Базисные и производные типы в SML Виды типизации. Контроль соответствия типов Преимущества теорий с типами Преимущества платформы .NET для контроля типов Библиография
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию существенного для любого подхода к программированию аспекта, а именно, типа. При этом будет особо отмечено то обстоятельство, что типизированные функции языков программирования естественным и интуитивно понятным образом моделируются посредством комбинаторов – ламбдавыражений специального вида с приписанными им типами. Далее будет представлено формальное введение в типизированный вариант комбинаторной логики, первоначально предложенный Х. Карри. Параллельно будут излагаться абстрактная математическая чистая система типов и ее конкретное представление в форме типизированной комбинаторной логики. По результатам представленной теории будут сделаны выводы о преимуществах и недостатках комбинаторной логики для моделирования конструкций языков функционального программирования со строгой типизацией. При этом существенное внимание будет уделено вопросам формализации выводимости типов и контроля типизации в языке функционального программирования SML, который изучается на протяжении всего курса. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Важнейшие работы в области типизации 1960-е – Р. Хиндли (Roger Hindley) исследовал типизацию в комбинаторной логике для моделирования языков функционального программирования со строгой типизацией 1969 – Р. Хиндли исследовал полиморфные системы типов 1978 – Р. Милнер (Robin Milner) предложил расширенную систему полиморфной типизации для ML
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним ход эволюции теорий, лежащих в основе современного подхода к типизации и теории типов. В 60-х г.г. Р. Хиндли (Roger Hindley) исследовал типизацию в комбинаторной логике. При этом основной проблемой, стоящей перед исследователем, было моделирование языков функционального программирования со строгой типизацией, к каковым, в частности, относится изучаемый нами язык SML. Позднее, в конце 60-х г.г., тот же ученый исследовал полиморфные системы типов, т.е. такие системы типов, в которых возможны параметризованные функции или функции, имеющие переменный тип. Наконец, в 70-х г.г. Р. Милнер (Robin Milner) предложил практическую реализацию расширенной системы полиморфной типизации для языка функционального программирования ML, давшего начало языку программирования SML.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Общие сведения о типизации Тип (сорт) – относительно устойчивая и независимая совокупность элементов, которую можно выделить во всем рассматриваемом множестве (предметной области). Задать тип T (как и любое множество) возможно: 1) явным перечислением элементов; 2) формализацией общих свойств элементов предметной области d∈D посредством индивидуализирующей предикатной функции Ψ, значение которой истинно, если элемент принадлежит данному типу и ложно в противном случае: T = {d: D|Ψ} © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перейдем к изложению начальных сведений из теории типов и типизации языков программирования. В математике принято называть типами (или, иначе, сортами) относительно устойчивые и независимые совокупности элементов, которые можно выделить во всем рассматриваемом множестве (предметной области). Заметим, что разделение элементов предметной области на типы или сорта во многом является условным и носит субъективный характер, т.к. зависит от эксперта в этой области. Тип, подобно множеству, может определяться двояко. Во-первых, возможно определение типа посредством явного перечисления всех элементов, принадлежащих типу (заметим, что такой подход применяется и в математике, и в программировании, где существуют так называемые перечислимые типы). Другим способом определения типа T является формализация общих свойств тех элементов d из предметной области D, которые объединяются в этот тип, посредством задания индивидуализирующей предикатной функции Ψ, значение которой истинно, если элемент принадлежит данному типу и ложно в противном случае: T = {d: D|Ψ}.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Типы в математике (1) Чистой системой типов называется семейство ламбдаисчислений, в которых каждый элемент характеризуется тройкой <S, A, R>, где: S – подмножество констант, называемых сортами; A – множество аксиом вида c:s, где с-константа, s-сорт; R – множество троек сортов, определяющих возможные функциональные пространства и их сорта для системы Приписывание ламбда-терму M типа T обозначим как #M |— T (читается: «ламбда-терм M имеет тип T») © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду При более формальном подходе к теории типов и типизации в связи с исчислением ламбда-конверсий следует определить чистую систему типов. Чистой системой типов называется семейство ламбда-исчислений, в которых каждый элемент характеризуется тройкой <S, A, R>, где: S – подмножество констант, называемых сортами; A – множество аксиом вида c : s, где с является константой, а s является сортом; R – множество троек сортов, определяющих возможные функциональные пространства и их сорта для системы. Далее введем обозначение, характеризующее то обстоятельство, что тот или иной объект является типизированным, или, иначе говоря, что тому или иному объекту приписан тип. В частности, для ламбда-терма M приписывание ему типа T обозначим как #M |— T и будем в таком случае говорить, что ламбда-терм M имеет тип T.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Типы в математике (2) Система типов формируется следующим образом: 1) задается множество базисных типов δ1, δ2, …; 2) всякий базисный тип считается типом; 3) если a и b считаются типами, то функция из a в b считается типом и имеет тип a→b. В основе теории типов лежит принцип иерархичности: производные типы содержат базисные как подмножества. Это справедливо и для языков программирования (аналогично строятся иерархии классов в ООП). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду При более общем подходе (который верен и для математики, и для программирования), система типов формируется следующим образом. Во-первых, задается множество базисных типов (обозначим их символами d1, d2, и так далее). Во-вторых, примем соглашение, что всякий базисный тип считается типом. Наконец, условимся, что если a и b считаются типами, то функция из a в b также считается типом и при этом имеет тип a→b. Заметим, что в основе теории типов лежит принцип иерархичности, который заключается в том, что производные типы содержат базисные как подмножества. Этот принцип построения остается справедливым и для языков программирования. В частности, иерархии классов в объектно-ориентированных языках программирования формируются аналогично вышеприведенному построению математической системы типов.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Свободные и связанные переменные Переменная x называется свободной в терме λx.A, если она имеет не имеет вхождений в терм A; в противном случае переменная x называется связанной Для составных термов связанность переменных определяется индукцией по построению. Терм, не содержащий свободных переменных, называется комбинатором. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для иллюстрации построения теории типов расширим комбинаторную логику операцией приписывания типа. Прежде всего, напомним определение комбинатора. Для того, чтобы формально определить комбинатор, необходимо ввести понятие свободной и связанной переменных в ламбда-выражении. Переменная x называется свободной в ламбда-выражении (терме) вида λx.A, если она не имеет вхождений в терм A; в противном случае переменная x называется связанной. Для составных ламбда-выражений понятие связанной и свободной переменной определяется индукцией по построению с учетом возможных способов комбинирования, а именно, операций аппликации и абстракции. Теперь становится возможным дать лаконичное определение комбинатора. Ламбда-выражение комбинатором.
(терм),
не
содержащее
свободных
переменных,
называется
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Комбинаторная логика: аксиомы и базис Следующие аксиомы задают свойства отношения конвертируемости (приводимости одного терма к другому), обозначаемого символом “=”. (I) Ix = x; (K) Kxy = x; (S) Sxyz = xz(yz). Множество (минимальной мощности) комбинаторов, через элементы которого выразим произвольный комбинатор, называется (минимальным) базисом. Пример минимального базиса: {K,S}. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним аксиомы конвертируемости:
комбинаторной
логики,
задающие
свойства
отношения
(I) Ix = x; (K) Kxy = x; (S) Sxyz = xz(yz). Аксиома (I) означает существование комбинатора (функции) тождества, т.е. наличие тождественного преобразования, при котором любой аргумент отображается сам в себя. Аксиома (K) означает существование комбинатора (функции) взятия первой проекции, т.е. первого элемента упорядоченной пары или первого элемента списка. Интуитивно ясно, что эта аксиома близка языкам функционального программирования, оперирующим списками, и соответствует фундаментальной операции взятия головного (первого) элемента списка. Напомним также о понятии базиса в комбинаторной логике: множество (минимальной мощности) комбинаторов, через элементы которого выразим произвольный комбинатор, называется (минимальным) базисом. Как оказывается, можно доказать, что: 1) базис термов для комбинаторной логики действительно существует (причем существует бесконечное множество возможных базисов); 2) для любого базиса справедливо, что он обеспечивает представление произвольного комбинаторного терма (в силу свойства полноты системы комбинаторной логики); 3) минимальный базис содержит два комбинатора, например, K и S. Приведем еще несколько примеров базисов: {I,K,S}; {I,B,C,S}; {B,W,K}.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Выводимость типов комбинаторов Тип a приписан комбинатору X тогда и только тогда, когда это утверждение получено из следующих аксиом (FI) |— #(I) = (a, a), (FK) |— #(K) = (a, (b,a)) = (a, b, a), (FS) |— #(S) = ((a, (b, c)), ((a, b)(a, c))) и правила вывода (F) если |— #(X) = (a, b) и |— #(U) = a, то |— #(XU) = b. Процедура контроля соответствия типов транслятора языка программирования работает аналогичным образом. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Оказывается, что комбинаторная логика обладает возможностью не только моделировать процесс реализации программного обеспечения на языке функционального программирования, но и прозрачно формализовать процедуру приписывания типов объектам этого языка. Под типом (или, иначе, сортом) будем понимать относительно устойчивую и независимую совокупность элементов, которую можно выделить во всем рассматриваемом множестве (предметной области). Более подробно типизация языков программирования и теория типов будут рассмотрены нами в ходе следующей лекции. В случае комбинаторной логики будем считать, что тип a приписан комбинатору X тогда и только тогда, когда это утверждение получено из следующих аксиом (FI) (FK) (FS)
|— #(I) = (a, a), |— #(K) = (a, (b,a)) = (a, b, a), |— #(S) = ((a, (b, c)), ((a, b)(a, c)))
и правила вывода (F)
если |— #(X) = (a, b) и |— #(U) = a, то |— #(XU) = b.
Заметим, что процедура контроля соответствия типов транслятора языка программирования реализована сходным образом, причем в ней существенно используется механизм сопоставления с образцом. В языке программирования SML, кроме того, применятся механизм получения логического вывода о типе выражения, исходя из контекста его использования. Этот механизм, известный также как выводимость типов (type inference), адекватно моделируется в терминах комбинаторной логики.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Типы в языке программирования SML (1) Каждому выражению (константа, переменная, функция) языка SML поставлен в соответствие тот или иной тип. Система типов в SML формируется по следующей схеме: 1) задается множество базисных типов: int - целые числа, string – строки символов, bool – логические значения, и .т.д.; 2) если a и b считаются типами, то функция из a в b имеет тип ‘a -> b’. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Сравним математическую теорию типов с подходом к типизации выражений, принятому в языке программирования SML. Каждому выражению (константа, переменная, функция) языка SML поставлен в соответствие тот или иной тип. Такая система типизации в языках функционального программирования называется системой сильной типизации, а сам язык – языком с сильной типизацией. Система типов в SML формируется по следующей схеме: Во-первых определяется множество базисных типов. В программирования SML выделяются следующие базисные типы: • int - целые числа; • string – строки символов, • bool – логические значения.
частности,
в
языке
Во-вторых, принимается следующее соглашение для выводимости производных типов: если a и b считаются типами, то функция из a в b имеет тип ‘a -> b’. Как нетрудно видеть, формирование системы типов в SML полностью аналогично построению системы типов в формальных математических теориях, в частности, в комбинаторной логике.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Типы в языке программирования SML (2) SML является языком со статической типизацией, т.е. тип выражения должен быть определен в процессе трансляции текста программы. Тип может быть задан явно либо выведен (type inference) из известных выражений, сопоставимых с данным (в ходе означивания функции, присваивания, и т.п.). В последнем случае задача логического вывода решается программой контроля соответствия типов (type checker), входящей в состав транслятора SML. В случае несоответствия типов инициируется сообщение об ошибке. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Язык функционального программирования SML является языком со статической типизацией. Это означает, что, процедура контроля типизации, которая является неотъемлемой частью транслятора любого современного языка программирования, должна поставить тот или иной тип в соответствие каждому выражению в тексте программы. Таким образом, приписывание типов выражениям происходит во время компиляции (compile time), а не во время выполнения (run time) программы, т.е. статически с точки зрения выполнения программы. Тот факт, что каждый объект программы должен быть типизирован до начала ее выполнения, не означает необходимости явного приписывания типа программистом в ходе проектирования и реализации программы. Важным преимуществом языка программирования SML, который, напомним, возник как инструментальное средство для доказательства теорем, т.е. построения цепочек логического вывода, является так называемое свойство выводимости типов (type inference). Это свойство означает, что тип некоторых выражений языка SML может быть выведен из контекста окружающих его выражений, типы которых уже известны, путем сопоставления (при этом учитываются объемлющие и внутренние функции, аппликация, присваивание и другие операции). При этом выводимость допускает не строгое равенство типов параметров, а лишь их сводимость друг к другу. С математической точки зрения прослеживается аналогия с отношением конвертируемости. В случае несоответствия типов сообщение об ошибке инициируется еще на стадии компиляции, что обеспечивает более упорядоченный и эффективный процесс проектирования и реализации программного обеспечения.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Типизация и полиморфизм в SML Язык программирования SML является языком с сильной типизацией, т.к. гарантирует обеспечение корректности типизации (что неверно, скажем, для языка C). Язык программирования SML является языком со статической типизацией, т.к. контроль соответствия типов осуществляется на этапе компиляции (в отличии от языка LISP). Язык программирования SML имеет полиморфную типизацию, т.к. допустимы функции переменного типа. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как уже отмечалось, язык функционального программирования SML является языком со строгой типизацией, т.е., говоря математическим языком, каждому выражению языка должен быть приписан тип. При этом гарантируется корректная типизация языковых объектов, что выгодно отличает SML от таких языков программирования, как, скажем, классический вариант C, в котором допускаются потенциально небезопасные для среды выполнения программы преобразования типов. Контроль соответствия типов в языке SML, в отличие от LISP и подобных ему языков программирования, в полном объеме осуществляется на этапе компиляции, что также способствует безопасности типизации. Еще одной важной позитивной особенностью языка программирования SML является то обстоятельство, что в нем поддерживается так называемая полиморфная типизация, суть которой можно объяснить на основе следующего примера. Рассмотрим функцию обработки списка, которая упорядочивает его элементы по возрастанию. В классическом языке программирования со строгой типизацией, например, в языке Pascal, неизбежно придется реализовать по крайней мере две функции: для случаев числовых и строковых элементов списка. В SML не возникает такой необходимости, т.к. существует возможность описания функции обработки списка с переменным типом аргументов, которая безошибочно обработает и список из чисел, и список из строк, существенно сэкономив трудозатраты.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Выводимость типов в SML Язык программирования SML поддерживает выводимость типов (type inference), иначе называемую let-полиморфизмом, гарантирующую безопасность вычислений. В частности, выражение let val Id = fn x => x in (Id 3, Id true) end является корректно типизированным в отличии от выражения fn Id => (Id 3, Id true)) (fn x => x) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем выводимость типов в языке программирования SML содержательным примером. Рассмотрим функцию let val Id = fn x => x in (Id 3, Id true) end С точки зрения анализатора корректности типизации эта функция является корректно типизированной (well-typed). Конструкция let, по сути, представляет собой подстановку одной функции в другую. В этой связи выводимость типов иначе называется letполиморфизмом. Рассмотрим другую функцию fn Id => (Id 3, Id true)) (fn x => x) В отличие от предыдущей, данная функция является некорректно типизированной (illtyped), поскольку однозначно определить тип параметра x, в отличие от предыдущего примера, не представляется возможным.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Преимущества типизации Модель предметной области лучше структурирована, существует иерархия сортов элементов Манипулирование элементами более целенаправленно, разнородные элементы обрабатываются различным образом, однородные - единообразно В случае строгой типизации несоответствия типов фиксируются до выполнения программы, гарантируя отсутствие смысловых ошибок и безопасность кода
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрев введение в математическую теорию типов и подходы к типизации в языках программирования, представим в концентрированном виде те преимущества, которые отличают языки программирования и формальные теории с типами. Прежде всего, отметим то бесспорное преимущество типизированных исчислений, что при таком подходе моделируемая предметная область области лучше структурирована, чем в том случае, если отсутствует сегментация на типы. Типизация структурирует предметную область по иерархическому принципу. Введение типизации облегчает и упорядочивает не только восприятие, но и управление предметной областью. Манипулирование типизированными элементами носит более целенаправленный характер, причем появляется возможность обрабатывать разнородные сущности предметной области различным образом, а однородные (или, точнее, однотипные) – единообразно. Перейдем к языкам программирования и практике проектирования и реализации программных систем. В случае построения языка программирования по принципу строгой типизации несоответствия типов фиксируются до начала этапа выполнения программы (на этапе контроля соответствия типов в ходе трансляции), что гарантирует отсутствие семантических (смысловых) и логических ошибок и безопасность программного кода.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Вычисление типов в SML (1) val x=2*3; (переменная) val x = 6 : int 1+2; (константа) 3: int fun add (x:int)(y:int) = x+y; (функция) val add = fn : int -> int -> int
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем на примерах механизм работы процедуры, осуществляющей вывод типов в языке программирования SML. В качестве первого примера определим тип статической переменной x, которой присвоим значение, сводимое к целому типу: val x=2*3; val x = 6 : int Как и следовало ожидать, значение переменной x оказывается целочисленным (int). Заметим, что функция val, которая используется в примере, является стандартной функцией языке программирования SML для определения типа языкового объекта, т.е. фактически осуществляет приписывание типа (при необходимости используя механизм выводимости типов). В качестве второго примера определим тип константы, которой присвоим значение, также сводимое к целому типу: 1+2; 3: int Как и следовало ожидать, значение константы 3 также оказывается целочисленным (int). Наконец, определим тип функции сложения двух целочисленных аргументов: fun add (x:int)(y:int) = x+y; val add = fn : int -> int -> int Как видно из результата, типом функции является функция из пары целочисленных значений в целочисленное значение (с точностью до скобок).
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Вычисление типов в SML (2) add 1 3; (вычисление значения функции) val it = 4: int val f = add 1; («частичная» функция) val f = fn : int -> int f 4; (композиция функций) val it = 5: int
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим ряд примеров. Проиллюстрируем означивание (вычисление значения) выше определенной функции сложения двух целочисленных аргументов: add 1 3; val it = 4: int Очевидно, что, как и следует из ранее вычисленного типа (int -> int -> int), функция, принимая на вход пару целочисленных величин, возвращает значение целочисленного типа. Рассмотрим далее тип функции, которая является производной от функции add и производит операцию прибавления единицы: val f = add 1; val f = fn : int -> int Вновь введенная функция имеет тип «из целого числа в целое число» (int -> int) . Наконец, означивание последней функции f 4; val it = 5: int в соответствии с ее типом дает целочисленный результат.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Полиморфизм типов в SML Встроенная функция hd для списка произвольного типа: hd [1, 2, 3]; val it = 1: int (тип функции: (int list) → int) hd [true, false, true, false]; val it = true: bool (тип: (bool list) → bool) hd [(1,2)(3,4),(5,6)]; val it = (1,2) : int*int ((int*int)list→(int*int)) Функция hd имеет тип (type list) →type, где type – произвольный тип © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим пример полиморфизма – оперирования функциями переменного типа. Для иллюстрации исследуем поведение встроенной функции hd, (от слова «head» – голова), которая выделяет «голову» (первый элемент) списка, вне зависимости от типа его элементов. Применим функцию к списку из целочисленных элементов: hd [1, 2, 3]; val it = 1: int Получим, что функция имеет тип функции из списка целочисленных величин в целое число (int list → int). В случае списка из значений истинности та же самая функция hd [true, false, true, false]; val it = true: bool возвращает значение истинности, т.е. имеет следующий тип: bool list →bool. Наконец, для случая списка кортежей из пар целых чисел hd [(1,2)(3,4),(5,6)]; val it = (1,2) : int*int В итоге можно сделать вывод о том, что функция получим тип ((int*int)list→ (int*int)). hd имеет тип (type list) → type, где type – произвольный тип, т.е. полиморфна.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Соответствие элементарных типов в SML и базовых классов .NET № п/п Тип SML int 1
Класс .NET System.Int32
Название типа Целое число Строка символов
2
string
System.String
3
bool
System.Boolean
…
…
…
Логическое значение …
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Технологическая платформа .NET обеспечивает единообразное управление типами элементов всех языков программирования, которые реализованы на этой платформе. Это достигается за счет интегрированной обобщенной системы типизации, так называемой Common Type System, или, сокращенно, CTS. Основная особенность CTS заключается в том, что она представляет собой единую иерархию типов, и типы объектов программы, написанной на произвольном языке программирования, который поддерживается технологической платформой .NET, в ходе трансляции автоматически преобразуются в соответствующие им типы Common Type System. Таким образом, для любого языка программирования существует отображение (функция), преобразующая произвольный тип этого языка в тот или иной тип Common Type System. Естественно, что язык программирования SML не является исключением. Приведем в подтверждение фрагмент отображения типов языка программирования SML в типы иерархии CTS, оформив это соответствие в виде таблицы. №
Тип
Класс .NET
Название типа
1
int
System.Int32
Целое число
2
string
System.String
Строка
3
bool
System. Boolean
Логическое значение
…
…
…
…
Позднее мы обсудим подобное соответствие типов для языка программирования C#.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Иерархия типов в .NET Общая система типов Common Type System (CTS) Типы-значения Встроенные типы-значения
Ссылочные типы Объектные типы
Интерфейсные типы
Типы указателей
Типы-значения и ссылочные типы, заданные пользователем © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более подробно обобщенную систему типизации, принятую в .NET. Как очевидно из схемы, Common Type System представляет собой иерархию, в которой стрелки указывают в сторону уменьшения общности типа. Типы иерархии CTS подразделяются на ссылочные типы (pointer type) и типы-значения (value type). Особенностями ссылочных типов являются необходимость использования указателей на типизированные объекты, а также централизованное хранение и освобождение памяти («сборка мусора»). Одной из характеристик типов-значений является то обстоятельство, что они не участвуют в наследовании. Кроме того, типы-значения копируются при присваивании значения. В свою очередь, ссылочные типы могут принимать одну из трех форм: 1) объектные типы (object type); 2) интерфейсные типы (interface type); 3) типы указателей (pointer type). В случае отсутствия стандартного типа нужной формы, пользователь имеет возможность конструирования собственного типа, который может быть как ссылочным типом, так и типом-значением. Система CTS обеспечивает безопасную типизацию, т.е. гарантирует отсутствие побочных эффектов (переполнение оперативной памяти компьютера, некорректное преобразование типов и т.д.).
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Преимущества типизации на платформе .NET 1. 2.
3.
4.
Использование централизованной, унифицированной системы типизации Common Type System (CTS) Строгое соответствие между примитивными типами языков программирования и базовыми классами .NET; встроенная поддержка примитивных типов большинством компиляторов для .NET Явное разделение на ссылочные типы (используются через указатель; централизованно хранятся и освобождаются) и типы-значения (не участвуют в наследовании; при присваивании значения копируются) Гибкий и надежный механизм преобразования типовзначений в ссылочные (boxing) и обратно (unboxing) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подводя итоги рассмотрения основных аспектов теории типов и типизации в языках программирования, можно сделать следующие выводы. Во-первых, теории с типами и языки программирования с типизацией имеют значительно более высокую вычислительную мощность, а, следовательно, более высокую теоретическую и прикладную значимость. Во-вторых, технологическая платформа .NET обеспечивает ряд несомненных дополнительных преимуществ перед другими известными платформами в отношении системы типов. В частности, технология .NET использует централизованную, унифицированную, интегрированную систему типизации Common Type System (CTS), общую для всех языков программирования, реализуемых на данной платформе. Кроме того, в рамках технологической платформы .NET обеспечивается строгое, однозначное соответствие между примитивными типами языков программирования и базовыми классами .NET. Большинством компиляторов для языков программирования, которые реализованы для платформы .NET, имеют встроенную поддержку примитивных типов. Целям безопасности типизации также служит явное разделение на ссылочные типы и типы-значения, а также гибкий и надежный механизм преобразования типов-значений в ссылочные (известный также под названием boxing) и обратно (известный также под названием unboxing).
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Библиография 1. 2.
3.
4.
Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 Hindley J.R., Seldin J.P. Introduction to combinators and λcalculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986 Milner R. A theory of type polymorphism in programming languages. Journal of Computer and System Science, 17(3):348-375, 1978 Hindley J.R. The principal type-scheme of an object in combinatory logic. Trans. Amer. Math. Soc., 146:29-60, 1969 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать такую многоаспектную и гибкую теорию, как теория типов. Мы ограничились рассмотрением лишь наиболее существенных аспектов формализации типизации в языках программирования, включая краткое знакомство с приписыванием типа, выводимостью типов и системой типизации, реализованной в .NET. Для более детального ознакомления с особенностями, достижениями и проблемами в области теории типов и типизации в языках программирования рекомендуется следующий список литературы: 1. Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 2. Hindley J.R., Seldin J.P. Introduction to combinators and λ-calculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986 3. Milner R. A theory of type polymorphism in programming languages. Journal of Computer and System Science, 17(3):348-375, 1978 4. Hindley J.R. The principal type-scheme of an object in combinatory logic. Trans. Amer. Math. Soc., 146:29-60, 1969 Кратко остановимся на источниках. Работа [1] является энциклопедией формальной системы комбинаторной логики, которая формализует типизацию в языках программирования. Работа [2] связывает ламбда-исчисление и комбинаторную логику. Работа [3] описывает систему полиморфной типизации для языков программирования. Работа [4] посвящена вопросам моделирования типизации объектов языков программирования в терминах комбинаторной логики.
Синтаксис языков программирования
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к понятийному аппарату, истории развития и выразительным возможностям синтаксического представления формальных теорий и языков программирования.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Содержание лекции 1. 2. 3. 4. 5. 6.
Понятие синтаксиса в математике и программировании Средства формализации синтаксиса. БНФ (формы Бэкуса - Наура) Обобщенная схема трансляции программы Синтаксис формальной теории (на примере ламбдаисчисления) Синтаксис базовых конструкций SML Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию синтаксического представления формальных теорий и языков программирования. При этом будет особо отмечено то обстоятельство, что в случае функционального подхода к программированию синтаксис языков программирования естественным и интуитивно понятным образом согласуется с соответствующей математической формализацией. Далее будет представлено неформальное введение в наиболее широко распространенную на сегодня математическую формализацию синтаксиса языка – формы Бэкуса-Наура или БНФ. Параллельно с синтаксисом формальной теории (на примере ламбда-исчисления) будет излагаться синтаксис языка программирования SML, ограниченный наиболее важными, основополагающими конструкциями. Существенное внимание будет уделено выявлению наиболее важных с точки зрения синтаксиса классов конструкций языка программирования SML, а также роли синтаксического анализа в процессе трансляции программы. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Важнейшие работы в области синтаксиса 1960-е – Х. Барендрегт (H. Barendregt) описал синтаксис ламбда-исчисления 1960-е – Дж. Бэкус (John Backus) создает и П. Наур (Peter Naur) дорабатывает метаязык (формы Бэкуса – Наура, БНФ) для формализации синтаксиса языка программирования ALGOL 60 1997 – Р. Милнер (Robin Milner) сформулировал современную версию синтаксиса языка программирования SML © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Неформально определим синтаксис (языка программирования или математической теории) как форму конструкций (программы или теории) и способов их комбинирования. Более точное определение синтаксиса будет сформулировано далее в ходе лекции. Кратко остановимся на наиболее значительных (с точки зрения данного курса) этапах эволюции теории и практики синтаксиса языков программирования. В 60-х г.г. Х. Барендрегтом (H. Barendregt) был детально описан синтаксис ламбдаисчисления – математической формализации, поддерживающей языки функционального программирования. Примерно в то же время Дж. Бэкусом (John Backus) были созданы основы формализации синтаксиса языков программирования посредством специального математического языка. Позднее П. Науром (Peter Naur) этот язык (а с точки зрения целевого языка программирования – метаязык) был доработан, в результате чего возникла математическая нотация, известная и сегодня под названием «форм Бэкуса-Наура», или, сокращенно, БНФ. Заметим, что эта нотация была специально разработана с целью для формализации синтаксиса языка программирования (в то время это был весьма популярный, прежде всего в математической среде, язык программирования ALGOL 60 с ясным, но довольно пространным синтаксисом). Заметим также, что формы Бэкуса-Наура или БНФ и в современных условиях являются теоретически адекватным и практически применимым средством формализации синтаксиса языков программирования. В 90-х г.г. синтаксис современного языка программирования SML был сформулировал Р. Милнером (Robin Milner). В работах, описывающих синтаксис SML, и по сей день широко используются формы Бэкуса-Наура.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Общие сведения о синтаксисе Синтаксис – это раздел описания формального математического языка или языка программирования, исследующий вид, форму и структуру конструкций (без учета их значения или практической применимости). Задать синтаксис языка возможно, перечислив описание его конструкций, например, с помощью БНФ. Ограничимся базовым набором конструкций языка, подчеркнув такие существенные возможности, как кортежи (tuples) и let-выражения. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Определим понятие синтаксиса более строго. Под синтаксисом понимают раздел описания формального математического языка или языка программирования, исследующий вид, форму и структуру конструкций (без учета их значения или практической применимости). Забегая вперед, заметим, что значение конструкций языка программирования описывается и исследуется семантикой (о ней речь пойдет в следующей лекции), а вопросы и ценность практической применимости – прагматикой. Основной задачей синтаксиса является определение формы и вида допустимых языковых конструкций. Эту задачу возможно решить путем перечисления описаний всех языковых конструкций. Одним из механизмов такого описания является уже упомянутая нами нотация БНФ. Мы будем рассматривать параллельно БНФ-формализации синтаксиса ламбда-исчисления и языка программирования SML. В последнем случае мы ограничимся базовым набором конструкций языка, подчеркнув такие существенные возможности, как кортежи (tuples), а также так называемые let-выражения.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Схема трансляции программы 1.
Лексический анализ: выделение в тексте программы элементарных конструкций-лексем (идентификаторов, ключевых слов, значений констант, переменных и др.).
2.
Синтаксический разбор: проверка корректности синтаксиса текста программы (возможно, включающая процедуру контроля соответствия типов).
3.
Преобразование текста программы в промежуточный или машинный код.
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для формирования правильного понимания роли и места синтаксиса в исследовании языков программирования, рассмотрим обобщенную схему трансляции исходного текста программы (написанной, например, на языке программирования SML) в машинный код. В ходе трансляции программы, прежде всего, выполняется так называемая процедура лексического анализа, которая включает в себя выделение в тексте программы элементарных конструкций языка, или, иначе, лексем (в частности, имен переменных или идентификаторов, специальных или ключевых слов, значений констант, переменных и др.). По завершении лексического анализа выполняется так называемая процедура синтаксического разбора текста программы, которая представляет собой проверку корректности синтаксиса текста, написанного на языке программирования. Эта процедура, возможно, включает выполнение проверки корректности типизации в той или иной форме. Наконец, в случае, если все конструкции языка, присутствующие в тексте программы, являются синтаксически корректными, а также не выявлено несоответствий типов, запрещенных с точки зрения анализатора корректности типизации, производится преобразование текста программы в промежуточный код (P-код, ассемблер, код той или иной абстрактной машины) или собственно машинный код.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Обозначения, принятые в БНФ Определяющий символ “::=“ разделяет определяемую конструкцию от составляющих ее ранее определенных базовых конструкций. Определяемая конструкция записывается слева от “::=“ в угловых скобках “<” и “>”. Альтернативы (возможные варианты) конструкций перечисляются по вертикали. Цитирование не имеет обозначения. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим синтаксис языка программирования SML в сравнении с синтаксисом ламбдаисчисления. Для большей наглядности и сопоставимости формализаций синтаксиса обоих языков (языка формальной математической теории и языка программирования) будем использовать единую нотацию, а именно, формы Бэкуса-Наура (БНФ). Прежде всего, необходимо договориться об обозначениях. Рассмотрим традиционные обозначения БНФ и поясним смысл каждого из них. Фактически БНФ представляют собой определения одних понятий через другие. При этом понятия заключаются в угловые скобки, и используется ряд специализированных символов и соглашений, суть которых поясняется далее. Определяющий символ “::=“ разделяет определяемую конструкцию от составляющих ее ранее определенных базовых конструкций. Определяемая конструкция записывается слева от “::=“ в угловых скобках “<” и “>”. Альтернативы (возможные варианты) конструкций перечисляются по вертикали. Цитирование (подобно тому, как мы цитировали специальные символы, заключая их в двойные кавычки) не имеет обозначения.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис ламбда-исчисления <выражение> ::= <константа> |
(константа)
<переменная> |
(переменная)
( <выражение> <выражение> ) |
(аппликация)
λ <переменная> . <выражение>
(абстракция)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем формализацию синтаксиса формальной системы посредством нотации БНФ, рассмотрев в качестве примера хорошо знакомое нам по предыдущим лекциям ламбда-исчисление. <выражение> ::= <константа> | <переменная> | ( <выражение> <выражение> ) | λ <переменная> . <выражение> Поясним смысл приведенных обозначений. В данном примере определяется понятие выражения, синтаксическое представление которого может быть выражено в виде одной из следующих альтернатив: 1) константы; 2) переменной; 3) двух выражений, заключенных в круглые скобки, т.е., знакомой нам операции аппликации ламбда-выражений; 4) символа λ, за которым следует переменная, точка и выражение, т.е. знакомой нам операции абстракции ламбда-выражений.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Важнейшие синтаксические категории SML Выражение – обозначение конструкции языка, которой может быть присвоено значение (константы, переменной, функции и т.д.). Описание – запись, связывающая выражение с его именем (идентификатором). Зарезервированное (служебное) слово – конструкция языка, однозначно интерпретируемая как инструкция языка программирования (например, “if”, “then”, “let”). В данной нотации используется без кавычек. Комментарий – произвольный поясняющий текст к программе, заключенный в ограничители “(*” и “*)”. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Оказывается, что синтаксис языка программирования SML имеет ряд очевидных аналогий с синтаксисом ламбда-исчисления. Эти аналогии являются неизбежными как в силу функциональной природы рассматриваемого языка программирования, так и на том основании, что язык SML разрабатывался как средство доказательства теорем, а, значит, его синтаксис (а, забегая вперед, заметим, что и семантика) должен быть прозрачен математически. Для иллюстрации перечисленных выше тезисов рассмотрим важнейшие синтаксические категории языка программирования SML. Под выражением будем далее понимать обозначение конструкции языка, которой может быть присвоено значение (константы, переменной, функции и т.д.). Описанием будем в дальнейшем называть запись, связывающую выражение языка программирования с именем, обозначающим его в программе (идентификатором). Под термином «зарезервированное» (или, иначе, служебное) слово будем иметь в виду конструкцию языка, однозначно интерпретируемую в качестве инструкции языка программирования (например, “if”, “then”, “let”). Напомним, что в данной нотации цитирование производится без кавычек или других символов-ограничителей. Комментарием назовем произвольный поясняющий текст к программе, который, согласно синтаксису языка SML положено заключать в ограничители вида “(*” и “*)”.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис SML: выражения (1) <выражение> ::= <идентификатор> | (имя объекта) <литерал> | <выражение> <выражение> |(аппликация) <выражение> <идентификатор> <выражение> (инфиксная аппликация)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение синтаксических категорий языка программирования SML. В частности, рассмотрим структуру основных синтаксически допустимых типов выражений языка. Приведем соответствующую формализацию в терминах БНФ. <выражение> ::= <идентификатор> | <литерал> | <выражение> <выражение> <выражение> <идентификатор> <выражение> | Как видно из БНФ-формализации, синтаксически корректным выражением в языке программирования SML считается: 1) идентификатор (т.е. имя переменной, константы, функции или типа, обычно представляемой в виде алфавитно-цифровой последовательности ограниченной длины и начинающейся с буквенного символа) или 2) литерал (литералы будут рассмотрены далее в ходе данной лекции) или 3) последовательность из двух выражений или 4) последовательность из двух выражений, соединенных идентификатором.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис SML: выражения (2) if <выражение> then <выражение> else <выражение>| (условное выражение) ( <выражение> ... <выражение> ) |
(кортеж)
let <описание> in <выражение> end |
(let-выражение)
( <выражение> )
(выражение в скобках)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение выражений. В дополнении к перечисленным на предыдущем слайде альтернативам, синтаксически допустимыми выражениями языка программирования SML, как следует из представленной БНФ, также являются: if <выражение> then <выражение> else <выражение>| ( <выражение> ... <выражение> ) | let <описание> in <выражение> end | ( <выражение> ) 5) три выражения, соединенные зарезервированными словами if («если»), then («тогда») и, else («в противном случае»), называемые условным выражением и фактически представляющие из себя предикатную функцию, которая реализует выполнение второго выражения в случае истинности первого и выполнение третьего в противном случае; 6) конечную последовательность выражений, заключенную в круглые скобки (или так называемый кортеж) и применяемую для структуризации данных; 7) описание и выражение, соединенные зарезервированными словами let («положим»), in («в») и end («конец»), которые определяют операцию подстановки описания в выражение с учетом всевозможных вхождений в него указанного фрагмента описания; 8) выражение, заключенное в круглые скобки (как мы уже знаем, в ламбдаисчислении и комбинаторной логике эту операцию можно производить без ограничений) и используемое для явного указания приоритета операции.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис SML: описания <описание> ::= val < идентификатор > = < выражение >
| (связывание переменной)
fun <идентификатор> <идентификатор> = < выражение > | (связывание функции) local < описание > in <описание> end (локальное описание)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение синтаксических категорий языка программирования SML. Перейдем к рассмотрению структуры синтаксически допустимых видов описаний объектов языка. Приведем соответствующую формализацию в терминах БНФ. <описание> ::= val < идентификатор > = < выражение >
|
fun < идентификатор > < идентификатор > = < выражение >
|
local < описание > in <описание> end Синтаксически допустимыми описаниями языка программирования SML, как следует из представленной БНФ, являются: 1) идентификатор и выражение, соединенные зарезервированными словами val и =, которые обозначают связывание идентификатора (переменной, константы или другого синтаксически допустимого объекта языка программирования с тем или иным выражением); 2) три идентификатора и выражение, соединенные зарезервированными словами fun и =, которые обозначают связывание функции (обозначенной первым идентификатором) с параметром (обозначенным вторым идентификатором) с выражением, которое определяет порядок вычисления значения; 3) два описания, соединенные зарезервированными словами local, in и end, которые обозначают локальное определение первого описания в контексте второго.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис SML: типы <тип> ::= (целые числа, неструктурированный тип)
int | bool |
(логические значения , неструктурированный тип)
<тип> * … * <тип> | <тип> -> <тип>
(кортежи, структурированный тип) (функции, структурированный тип)
Кортеж(0,false,1,true)имеет тип(int*bool*int*bool).
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение синтаксических категорий языка программирования SML. Перейдем к рассмотрению структуры синтаксически допустимых видов описаний типов объектов языка. Приведем соответствующую формализацию в терминах БНФ. <тип> ::=
int | bool | <тип> * … * <тип> | <тип> -> <тип>
Как следует из представленной БНФ, синтаксически допустимыми типами языка программирования SML являются: 1) целочисленные величины, обозначаемые зарезервированным словом int; 2) логические значения, обозначаемые зарезервированным словом bool; 3) кортежи – упорядоченные n-ки элементов определенных типов; 4) функции – упорядоченные n-ки элементов определенных типов, соединенных зарезервированными символами ->. Рассмотрим следующий пример, иллюстрирующий приписывание типов в языке SML. Константа типа кортеж вида (0,false,1,true) имеет тип (int*bool*int*bool). Заметим, что варианты типов (1) и (2) являются элементарными, тогда как (3) и (4) представляют собой производные типы с явно указанной (или выводимой) структурой, откуда и происходит название «структурированный тип».
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис SML: литералы <литерал> ::= <литерал целого типа> | (целое число int, диапазон от –230 до +230) <литерал строкового типа> | (строка ASCII-символов string) <литерал вещественного типа> (вещественное число real) Замечание. Значение литерала полностью определяется его лексическим представлением. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции нами уже упоминалось о такой синтаксической категории как литералы, или, как следует из их названия, о базовых типах SML, состоящих из определенных последовательностей символов. Рассмотрим подробнее синтаксические особенности основных видов литералов. Приведем соответствующую формализацию в терминах БНФ. <литерал> ::= <литерал целого типа> | <литерал строкового типа> | <литерал вещественного типа> Как следует из представленной БНФ, синтаксически допустимыми типами литералов в языке программирования SML являются следующие: 1) целочисленные литералы, имеющие тип int и лежащие в диапазоне от –230 до +230 (последнее обстоятельство связано с особенностями машинного представления данных); 2) строковые литералы, имеющие тип string и представляющие собой алфавитноцифровые последовательности символов в коде формата ASCII; 3) вещественные литералы, имеющие базовый тип real, обобщенную форму вида M x 10E, где M – мантисса в диапазоне от –1 до +1, а E – порядок в соответствующем диапазоне. Заметим, что значение (т.е. семантика) литералов в полной мере определяется их лексическим (а, значит, и синтаксическим) представлением.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис SML: аппликация функции <выражение> <выражение> Аппликация выполнима для ранее определенной функции. Например, для функции с определением fun succ n = n+1 аппликация может иметь вид succ 2 и значение 3.
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение синтаксических категорий языка программирования SML. Перейдем к рассмотрению фундаментальной с точки зрения формализации языков функционального программирования – ламбда-исчисления – операции аппликации функций. Приведем соответствующую формализацию в терминах БНФ: <выражение> <выражение> Как следует из представленной БНФ, синтаксически допустимая конструкция языка программирования SML, описывающая операцию аппликации, весьма точно соответствует описанию операции аппликации выражений в ламбда-исчислении. Проиллюстрируем аппликацию функции к аргументу в языке программирования SML следующим примером. Рассмотрим функцию succ, которая задается следующим определением fun succ n = n+1 и осуществляет прибавление единицы к (целочисленному) аргументу. Для рассматриваемой функции succ синтаксически корректная аппликация может иметь вид succ 2 и вычисляться в ходе выполнения программы в значение 3.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис SML: условное выражение if <выражение> then <выражение> else <выражение>
Результатом вычисления первого выражения должно быть логическое значение. Типы второго и третьего выражений должны совпадать. Часть, начинающаяся с else, не является обязательной. Встроенные функции сравнения имеют вид: “=”, “<”, “>”, “<=”, “>=”, “<>”. Результатом их вычисления является логическое значение. Пример: if n>=10 then 1 else 0 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение синтаксических категорий языка программирования SML. Перейдем к рассмотрению синтаксически допустимых программирования SML, называемых условными выражениями.
конструкций
языка
Приведем соответствующую формализацию в терминах БНФ: if <выражение> then <выражение> else <выражение> Как видно из БНФ-формализации, синтаксически корректное условное выражение состоит из трех подвыражений, соединенных зарезервированными словами if, then и else, уже упоминавшихся нами в ходе лекции. Добавим к ранее сказанному ряд необходимых замечаний. Во-первых, результатом вычисления первого выражения должно быть логическое значение. Во-вторых, типы второго и третьего выражений должны совпадать. Наконец, часть условного выражения, начинающаяся с else, не является обязательной. Заметим также, что функции сравнения встроены в язык SML и имеют вид: “=” (равно), “<” (меньше), “>” (больше), “<=” (меньше или равно), “>=” (больше или равно), “<>” (не равно). Результатом вычисления любой из этих функций является логическое значение. Проиллюстрируем синтаксис условного выражения следующим примером на языке SML: if n>=10 then 1 else 0 Заметим, что приведенное выражение может использоваться для анализа параметра функции, вычисляющей, например, количество разрядов десятичного числа.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис SML: let-выражение let <описание> in <выражение> end Область действия: от in до end. Используется для связывания значений и оптимизации сложных вычислений. Пример 1: let val n=2 in n+1 end Пример 2. let k 9876*8765 in (k-1, k, k+1) end Замечание. Умножение в последнем примере выполняется однократно. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение основных синтаксических категорий языка программирования SML. Рассмотрим структуру синтаксически допустимых конструкций, известных под названием let-выражений. Приведем соответствующую формализацию в терминах БНФ: let <описание> in <выражение> end Как видно из БНФ-формализации, синтаксически корректное let-выражение состоит из описания и выражения, соединенных зарезервированными словами let, in и end. Как можно заключить из синтаксиса, let-выражение представляет собой ни что иное, как подстановку значения в ламбда-абстракцию. Let-выражения используются в языке программирования SML для связывания значений и оптимизации вычислений, в частности, обеспечивая однократное вычисление повторяющихся фрагментов программы. Проиллюстрируем синтаксис let-выражений примерами из языка программирования SML. Рассмотрим следующие let-выражения: let val n=2 in n+1 end; let k 9876*8765 in (k-1, k, k+1) end; Как можно видеть, первое выражение представляет собой ни что иное, как подстановку, которую можно формализовать ламбда-термом вида (λx. x + 1) 2. Второе выражение позволяет свести многократное вычисление громоздкой операции (умножения) к однократному.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис SML: кортеж и выражение в скобках Кортежем называется группа по меньшей мере из двух выражений (возможно, разного типа), объединенная в обособленную совокупность. (<выражение>, …, <выражение>)
Примеры: (1, 2*1, 2*2*1) (1, true, 0, false) В случае единственного выражения кортеж вырождается в выражение в скобках. Замечание. Любое SML-выражение можно заключить в скобки, например, для явного указания приоритета операций. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции неоднократно упоминалось понятие кортежа. Рассмотрим подробнее этот весьма важный (в особенности при реализации функций) вид синтаксических конструкций языка программирования SML. Приведем формализацию синтаксически допустимого представления кортежа в терминах БНФ: (<выражение>, …, <выражение>) Исходя из вида БНФ-формализации, уточним понятие кортежа. Кортежем называется группа, состоящая, по меньшей мере, из двух выражений (возможно, имеющих разные типы), объединенная в обособленную совокупность. Заметим, что кортежи используются в SML для реализации многоместных (имеющих более одного аргумента) функций, а более широко в теории и практике программирования – в реляционных базах данных (в которых данные представляются в виде таблиц), поскольку кортеж представляет собой, по сути, строку такой таблицы. Проиллюстрируем синтаксис программирования SML: Пример 1: Пример 2:
конструкции
кортежа
примерами
из
языка
(1, 2*1, 2*2*1) (1, true, 0, false)
Заметим, что в случае единственного выражения кортеж вырождается в выражение в скобках. Естественно, что любое SML-выражение можно заключить в скобки, например, для явного указания приоритета аппликаций, арифметических и логических операций.
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Синтаксис SML: описание переменной и функции Описание переменной связывает переменную со значением: <описание> ::= val <идентификатор> = <выражение>
1) 2) 3)
Описание функции аналогично описанию переменной и используется для определения и именования функции: <описание> ::= fun <идентификатор> <идентификатор> = <выражение> Примеры: val x=2; fun fact n = if n<2 then 1 else n * fact (n - 1); fun f (x,y) = x*x + y*y; Все функции SML одноместные. При необходимости использования многоместных функций используются кортежи, как в примере 3. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Полученный в ходе лекции опыт рассмотрения основных видов синтаксических конструкций языка программирования SML позволяет перейти к формальному синтаксису таких фундаментальных языковых конструкций как описания переменных и функций. Рассмотрим формализации синтаксически корректных описаний переменных и функций в терминах БНФ: <описание> ::= val <идентификатор> = <выражение> <описание> ::= fun <идентификатор> <идентификатор> = <выражение> Первое определение представляет собой описание переменной, второе – функции. При этом оба определения имеют сходную структуру. Проиллюстрируем формальные содержательными примерами:
описания
переменных
и
функций
следующими
Пример 1. val x=2; Пример 2. fun fact n = if n<2 then 1 else n * fact (n - 1); Пример 3. fun f (x,y) = x*x + y*y; Первый из приведенных примеров представляет собой описание (целочисленной) переменной x, второй – рекурсивной (самоприменимой) функции fact вычисления факториала (произведения натуральных чисел от 1 до n), а третий – двухместной функции f, вычисляющей сумму квадратов аргументов. Заметим в заключение, что именно при реализации последней функции используются кортежи (поскольку синтаксис SML в «чистом» виде, как следует из БНФ, допускает использование только одноместных функций).
Современные языки программирования и .NET: I семестр Лекция 7: Синтаксис языков программирования
Библиография 1. 2. 3. 4.
Barendregt H.P. The lambda calculus (revised edition), Studies in Logic, 103, North Holland, Amsterdam, 1984 Naur P. Revised report on the algorithmic language ALGOL 60. Communications of ACM 6, 1-17, 1963 Knuth D.E. Backus normal form vs. Backus Naur form. Comm. ACM 7:12 p.p. 735-736 Milner A.J.R.G. A proposal for Standard ML. Proceedings of the ACM Symposium on LISP and Functional Programming, Austin, 1984. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Итак, в данной лекции были рассмотрены основные виды синтаксических конструкций языка программирования SML. По итогам обсуждения можно сделать следующие выводы: 1) синтаксис языков функционального программирования достаточно близок к синтаксису формальных теорий, на которых они основаны (в частности, это справедливо для ламбда-исчисления и языка SML); 2) БНФ являются актуальной и адекватной формализацией синтаксиса языка; 3) язык программирования SML, в отличие от ранних языков функционального программирования, имеет ряд расширенных конструкций (кортежи, let-выражения и др.). К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать синтаксис языка программирования (даже учитывая тот факт, что синтаксис SML весьма лаконичен и занимает в чистом виде около четырех страниц текста). Для более детального ознакомления с особенностями, достижениями и проблемами в области синтаксиса языка программирования SML рекомендуется следующий список литературы: 1. Barendregt H.P. The lambda calculus (revised edition), Studies in Logic, 103, North Holland, Amsterdam, 1984 2. Naur P. Revised report on the algorithmic language ALGOL 60. Communications of ACM 6, 1-17, 1963 3. Knuth D.E. Backus normal form vs. Backus Naur form. Comm. ACM 7:12 p.p. 735-736 4. Milner A.J.R.G. A proposal for Standard ML. Proceedings of the ACM Symposium on LISP and Functional Programming, Austin, 1984 Кратко остановимся на источниках. Работа [1] является энциклопедией ламбдаисчисления, которое формализует языки функционального программирования. В работах [2,3] рассматриваются вопросы, связанные с развитием БНФ и их применением для формализации синтаксиса языков программирования. Работа [4] содержит развернутое описание синтаксиса языка функционального программирования SML.
Семантика языков программирования
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к понятийному аппарату, истории развития, существующим подходам и выразительным возможностям семантического представления формальных теорий и языков программирования.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Содержание лекции 1. 2. 3. 4. 5. 6. 7.
Понятие семантики в математике и программировании Виды семантик. Возможные подходы к исследованию семантики Средства формализации семантики Теория вычислений Д. Скотта. Конструкторы доменов Синтаксис базовых конструкций SML Денотационная семантика базовых конструкций SML Библиография
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию семантического представления формальных теорий и языков программирования. При этом будет предпринята попытка классификации существующих видов семантики. Далее будет представлено неформальное введение в наиболее адекватный целям данного курса и достаточно широко распространенный на сегодня подход к семантике, а именно, так называемый денотационный подход. Теоретические рассуждения о семантике в формальных теориях (на примере теории вычислений Д.Скотта) будут проиллюстрированы представлением денотационной семантики подмножества языка программирования SML, ограниченного наиболее важными, основополагающими конструкциями. При этом существенное внимание будет также уделено сопоставлению и сравнительному анализу синтаксического и семантического аспектов наиболее важных с точки зрения программирования классов конструкций языка программирования SML. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Важнейшие работы в области семантики (1) 1960-е – Х. Барендрегт (H. Barendregt) описал семантику ламбда-исчисления 1969 – Д. Скотт (Dana S. Scott) предложил использовать домены (особый вид множеств) для формализации денотационной семантики как функции вычисления значения синтаксически корректных конструкций языка 1979 – М. Гордон (Michael J.C. Gordon) исследовал денотационную семантику языков программирования © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко остановимся на наиболее значительных (с точки зрения данного курса) этапах эволюции теории и практики семантического анализа языков программирования. В 60-х г.г. Х. Барендрегтом (H. Barendregt) была детально описана семантика ламбдаисчисления – математической формализации, поддерживающей языки функционального программирования. Позднее, в конце 60-х г.г., Д. Скоттом (Dana S. Scott) было предложено использовать для формализации семантики математических теорий так называемые домены (пока будем неформально понимать их как особый вид множеств). При этом на основе доменов Д. Скоттом был предложен так называемый денотационный подход к семантике. Такой подход предполагает анализ синтаксически корректных конструкций языка (или, иначе, денотатов) с точки зрения возможности вычисления их значений посредством специализированных функций. Далее, в 70-х г.г., М. Гордоном (Michael J.C. Gordon) был исследован аппарат денотационной семантики применительно к языкам функционального программирования и сделал вывод об адекватности и практической эффективности применения этого подхода для решения поставленной задачи.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Важнейшие работы в области семантики (2) 1964 – П. Лендин (Peter J. Landin) разработал семантику модели языка программирования в форме абстрактной машины на состояниях 1969 – Ч. Хоар (Charles A.R. Hoare) создал аксиоматический метод, моделирующий операторы языка программирования 1960-е – Р. Флойд (Robert W. Floyd) создал метод индуктивных утверждений для формализации семантики протекания информации в программе (графическая иллюстрация - блок-схемы) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Параллельным направлением изучения семантики был подход, исследовавший изменения, которые происходили в процессе работы программы на основе отслеживания смены состояний программы. Одним из практических результатов работ в этом направлении стала разработка П. Лендином (Peter J. Landin) семантики модели языка программирования в форме абстрактной машины, существенно использовавшей понятие состояния. Альтернативный подход к формализации семантики (который был осуществлен в рамках исследования так называемой операционной семантики языков программирования) привел к созданию Ч. Хоаром (Charles A.R. Hoare) аксиоматического метода, моделирующего отношения и причинно-следственные связи, возникающие между операторами языка программирования. Развитие операционной семантики языков программирования привело Р. Флойда (Robert W. Floyd) к созданию так называемого метода индуктивных утверждений, который использовался для формализации семантики протекания информации в программе. При этом существенным преимуществом предложенного Р. Флойдом метода стала возможность интуитивно прозрачной и наглядной графической иллюстрации, основанной на блок-схемах, формализующих последовательность протекания информации.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Общие требования к описанию языков программирования 1)
полнота: синтаксис и семантика всех допустимых конструкций должны быть описаны без пропусков;
2)
ясность: удобочитаемость, легкость и результативность поиска ответов на вопросы;
3)
естественность: интуитивная близость пользователю, использование стандартных обозначений;
4)
реализм: учет ограничений на объем оперативной памяти, время реакции и т.д. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перейдем к рассмотрению неформальной семантики языков программирования. Для построения адекватной и удобной в использовании семантики необходимо, прежде всего, определить критерии, характеризующие «хороший» язык программирования. Попытаемся сформулировать обобщенные требования, предъявляемые к описанию языков программирования. Во-первых, необходимо потребовать от языка программирования соблюдения принципа полноты, т.е. оснастить язык программирования таким набором конструкций, который позволяет описать синтаксис (и семантику) всех допустимых конструкций языка без пропусков существенных аспектов. Во-вторых, язык программирования должен удовлетворять интуитивному требованию ясности, а именно, объективно обеспечивать удобочитаемость программ, а также легкость и результативность поиска ответов на вопросы, возникающие в процессе разработки программных проектов. Немаловажной характеристикой языка программирования является естественность, под которой мы будем понимать интуитивную близость языка к терминологии разработчика, а также использование унифицированных, стандартных, привычных обозначений. Наконец, необходимо учитывать и такой важный параметр, как реализм, который понимается как учет естественных ограничений на среду реализации языка программирования, а именно: объем оперативной памяти, время реакции и целый ряд других существенных факторов.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Общие сведения о семантике (1) Семантикой называется интерпретация (т.е. смысловое значение) абстрактного синтаксиса (т.е. множества допустимых конструкций языка), выраженное в терминах той или иной математически строгой модели. 1) 2)
Основные подходы к семантике: ориентированные на компиляцию (семантика – множество преобразований над синтаксической моделью); ориентированные на интерпретацию (семантика – множество описанных на метаязыке преобразований синтаксически правильных языковых конструкций). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду После обсуждения обобщенных и концептуально важных требований к языкам программирования в целом, перейдем к неформальному обсуждению семантического подхода, способного обеспечить реализацию этих требований. Прежде всего, расширим наивное представление о семантике языка программирования (или формальной теории) хотя и предварительным, но более конкретным определением этого понятия. Семантикой будем называть интерпретацию (или, иначе, смысловое значение) абстрактного синтаксиса (а точнее, множества допустимых видов конструкций языка), представленное в терминах той или иной математически строгой формальной модели. Как оказывается, все многообразие возможных подходов к семантике можно в основном представить всего двумя типами семантик, а именно, семантиками, ориентированными на компиляцию и семантиками, ориентированными на интерпретацию. В дальнейшем под подходами к семантике, ориентированными на компиляцию, будем понимать такие подходы, в которых семантика представляет собой множество преобразований над синтаксической моделью в той или иной форме. В отличие от предыдущего подхода, под подходами к семантике, ориентированными на интерпретацию, будем понимать такие подходы, в которых семантика представляет собой множество описанных на специально построенном метаязыке преобразований синтаксически правильных конструкций языка программирования.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Общие сведения о семантике (2) Виды семантик, ориентированные на интерпретацию: 1)
2)
3)
Операционные (смысл конструкций языка в терминах переходов абстрактной машины из одного состояния в другое), например, SECD-машина П. Лендина; Пропозиционные (смысл конструкций языка в терминах множества формул, описывающих состояния объектов программы), например, подходы Хоара и Флойда; Денотационные (смысл конструкций языка в терминах абстракции функций на состояниях программы), например, теория семантических доменов Д. Скотта. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Сразу заметим, что целям нашего курса в большей степени соответствует второй подход, как более универсальный в силу того обстоятельства, что в нем используется метатеория, т.е. формализация, моделирующая преобразования текста программ. Выделим основные направления, существующие в рамках подхода к семантике, ориентированного на интерпретацию и свяжем их с рассмотренными нами в ходе лекции направлениями исследований. Оказывается, что существуют три основных вида семантик, ориентированных на интерпретацию. Во-первых, необходимо упомянуть об операционных семантиках. Значение конструкций языка в таких семантиках выражается в терминах переходов той или иной абстрактной машины из одного состояния в другое. В качестве показательных примеров абстрактных машин можно привести, в частности, так называемую SECD-машину П. Лендина, а также категориальную абстрактную машину. Обе формализации будут рассмотрены подробнее в ходе дальнейших лекций. Другим типом семантик, ориентированных на интерпретацию, являются так называемые пропозиционные семантики. В отличие от операционных семантик, значение конструкций языка в таких семантиках выражается в терминах множества формул, описывающих состояния объектов программы. В качестве примеров можно, привести, в частности, аксиоматический метод Хоара и метод индуктивных утверждений Флойда. Наконец, наиболее значимым для нас типом семантик, ориентированных на интерпретацию, являются денотационные семантики, в которых смысл конструкций языка представляется в терминах абстракции функций, оперирующих состояниями программы. В частности, данный подход иллюстрирует теория вычислений Д. Скотта, основанная на семантических доменах, которую и предлагаем вашему вниманию.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Теория вычислений Д. Скотта Создана в 1969 г. для непротиворечивой формализации семантики языков на основе алгебры доменов – аналогов множеств, адекватно моделирующих самоприменимые функции и множества. 1) 2) 3)
Последовательность построения теории: перечисление стандартных (наиболее часто используемых) доменов; определение конечных доменов с явно перечисляемыми элементами ; определение конструкторов (способов комбинирования) доменов. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним, что теория вычислений Д. Скотта была создана до появления большинства современных языков программирования, а именно в конце 60-х г.г. Существенно, что именно эта теория (в отличие от, скажем, классической логики и ряда других формальных систем) позволяет произвести адекватную (а именно, полную и непротиворечивую) формализацию семантики языков программирования. Теория вычислений Д. Скотта основана на фундаментальном понятии домена, который будем пока неформально понимать как некоторый аналог множества, впрочем, в отличие от традиционных множеств, адекватно формализующий рекурсивно (т.е. на основе самоприменения) определенные функции и множества. Сформулируем последовательность изложения теории вычислений Д. Скотта. Для построения теории вычислений необходимо, во-первых, перечислить так называемые стандартные, или, точнее, наиболее часто используемые в рамках данной формализации, домены. После перечисления стандартных доменов необходимо определить так называемые конечные домены, или, точнее, домены, элементы которых возможно перечислить явным образом. Наконец, после перечисления доменов перейдем к определению конструкторов доменов, под которыми понимаются операции построения новых доменов на основе имеющихся, или, иначе, определим способы комбинирования доменов.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Конструкторы доменов 1)
Функциональное пространство: [D1→D2]={f|f: D1→D2};
2)
Декартово произведение – домен всевозможных n-ок: [D1×D2×…×Dn]={(d1×d2×…×dn)|d1∈D1, d2∈D2 , dn …, ∈Dn};
3)
Последовательность D*- домен всех конечных последовательностей вида d=(d1,d2,…,dn) из элементов d1,d2,…,dn,… домена D, где n>0;
4)
Дизъюнктная сумма [D1+ D2 + … + Dn]={(di,i)| di∈Di, 0
Комментарий к слайду Перечислив основные типы элементарных доменов, перейдем к их комбинированию посредством конструкторов. Заметим, что, подобно ламбда-исчислению и комбинаторной логике, теория вычислений обладает весьма лаконичным набором способов комбинирования доменов. Как мы увидим далее, существуют всего четыре типа конструкторов. Тем не менее, такой набор является вполне достаточным для построения домена, моделирующего семантику сколь угодно сложной предметной области или языка программирования. Приведем определения перечисленных способов комбинирования доменов. Под функциональным пространством из домена D1 в домен D2 будем понимать домен [D1→D2], содержащий всевозможные функции с областью определения из домена D1 и областью значений из домена D2: [D1 → D2] = {f | f : D1 → D2}. Под декартовым (или, иначе, прямым) произведением доменов D1, D2, … Dn будем понимать домен всевозможных n-ок вида [D1×D2×…×Dn]={(d1×d2×…×dn) | d1∈D1, d2∈D2 , dn …, ∈Dn}. Под последовательностью D* будем понимать домен всевозможных конечных последовательностей вида d=(d1,d2,…,dn) из элементов d1,d2,…,dn,… домена D, где n>0. Наконец, под дизъюнктной суммой будем [D1+D2+…+Dn]={ (di, i) | di ∈Di, 0
понимать
где принадлежность элементов di компонентам специальными функциями принадлежности.
домен
с
определением
Di однозначно устанавливается
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Синтаксис подмножества SML Формализуем синтаксис (а затем и семантику) языка SMalL – весьма ограниченного подмножества SML: E::=true|false|0|1|I|~E|E1==E2|E1+E2 (выражение) С::=I=E|if(E)C1 else C2|while(E) C|C1;C2 (команда)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Поставим задачу формализации семантики языка функционального программирования SML. Заметим сразу, что в рамках данного курса будет рассматриваться не все множество возможных конструкций данного языка, а некоторое весьма ограниченное (хотя и вполне достаточное для иллюстрации основных идей курса) их подмножество, которое условно назовем языком программирования SmalL и будем именовать так в дальнейшем. Прежде всего, рассмотрим синтаксис языка SmalL, т.е. перечислим основные типы конструкций, составляющих его. Язык SmalL содержит множество выражений E, которые формализуются посредством БНФ в следующем виде: E ::= true | false | 0 | 1 | I | ~E | E1==E2 | E1+E2 Заметим, что выражения включают логические (true и false) и целочисленные (в ограниченном объеме: 0 и 1) константы, множество идентификаторов (I), а также операции отрицания (~E), сравнения (E1==E2) и сложения (E1+E2). Кроме того, язык SmalL содержит множество команд С, которые формализуются посредством БНФ в следующем виде: С ::= I=E | if(E)C1 else C2 | while(E) C | C1;C2 Заметим, что команды включают присваивание (I=E), условие (if(E)C1 else C2), цикл с предусловием (while(E) C), а также последовательность команд (C1;C2). Деление синтаксиса языка SmalL на выражения и команды во многом является условным и служит иллюстративным целям.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Семантика подмножества SML (1) 1) 2) 3) 4)
Порядок построения семантики – теории вычислений: определение синтаксических доменов (Ide, Exp и Com); определение вычислительной модели; определение семантических функций E, C и т.д. для отображения синтаксических конструкций в семантические; определение семантических предложений. При выполнении SMalL-программы происходит изменение состояния, состоящего из памяти (m, memory), которая характеризует соответствие идентификаторов и значений (связывание) либо имеет значение unbound. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как уже отмечалось, в качестве математической формализации, моделирующей семантику языков программирования (в частности, языка SMalL), будет использоваться теория вычислений Д. Скотта. Приведем порядок построения формальной модели семантики языка программирования SmalL согласно ранее представленному формальному описанию синтаксиса языка в терминах БНФ. Прежде всего, необходимо дать определение синтаксических доменов (т.е. доменов, характеризующих основные синтаксические категории) для идентификаторов (домен Ide), выражений (домен Exp) и команд (домен Com). Далее, следует представить синтаксических доменов.
определение
вычислительной
модели
на
основе
Затем, необходимо перейти к определению семантических функций (E для домена Exp, C для домена Com и т.д.), которые отображают синтаксические конструкции языка программирования в соответствующие им семантические представления. Наконец, следует сформулировать определение семантических предложений в терминах смены состояний программы. Заметим, что при выполнении программы (в частности, написанной на языке программирования SMalL) происходит изменение состояния, состоящего из памяти (m, memory), которая в простейшем случае характеризует соответствие идентификаторов и значений (то есть, по сути, связывание переменной со значением) либо имеет значение unbound (характеризующий отсутствие связи идентификатора со значением, т.е. аналогичный свободной переменной).
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Семантика подмножества SML (2) Синтаксис определяется синтаксическими доменами: Ide = {I|I - идентификатор}; Com = {C|C- команда}; Exp = {E|E- выражение}. Состояние: Параметр Домен Состояние State Память Memory
Соотношение (s) State = Memory
Значение
(v)Value=Int+Bool
Value
(m) Memory=Ide→[Value+{unbound}]
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В соответствии с намеченной схемой рассуждений, перейдем к описанию синтаксических доменов, которые в полной мере определяют синтаксис языка SMalL: Ide = {I | I – идентификатор}; Com = {C | C – команда}; Exp = {E | E – выражение}. Совокупность всех возможных идентификаторов языка SMalL организуем в домен Ide, команд – в домен Com, и, наконец, выражений – в домен Exp. Далее, сформулируем вычислительную модель на основе состояний программы языка SMalL, для наглядности систематизировав ее в виде следующей таблицы: Параметр
Домен
Состояние
State
Память
Memory
Значение
Value
Соотношение (s) State = Memory (m) Memory = Ide → [ Value + {unbound} ] (v)Value = Int + Bool
Заметим, что состояние программы в произвольный момент времени определяется состоянием «памяти» абстрактной машины той или иной формы. При этом под памятью понимается отображение из домена идентификаторов в домен значений (т.е. аналог связывания переменной со значением в ламбда-исчислении). Для корректной обработки исключительных ситуаций, возникающих в случае свободных переменных, вводится дополнительный элемент unbound. Домен значений представляет собой дизъюнктную сумму доменов, содержащих существующие в языке SMalL типы Int и Bool.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Семантика подмножества SML (3) Семантические предложения для денотатов выражений: E : Exp → [State →[[Value × State] + {error}]]; E[E]s = (v,s’), если v - значение E в s, s’-состояние после означивания; E[E]s = error, если возникает ошибка несоответствия типов. Семантические предложения для денотатов команд: С : Com → [State →[ State + {error}]] © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В соответствии с намеченной схемой рассуждений, перейдем к описанию семантических предложений, которые описывают значение денотатов (т.е. правильно построенных конструкций) языка SMalL. Приведем семантические предложения для выражений языка программирования SMalL: E : Exp → [State → [[Value × State] + {error}]]; E[E]s = (v,s’), если v – значение E в s, s’– состояние после означивания; E[E]s = error, если возникает ошибка несоответствия типов. Из приведенных соотношений следует, что вычисление значения выражения языка программирования SMalL приводит к такому изменению состояния, что происходит связывание переменной со значением, либо (в случае невозможности связывания по причине несоответствия типов переменной и значения) вырабатывается ошибка. При этом состояние программы изменяется с s на s’. Приведем семантические предложения для команд языка программирования SMalL: С : Com → [State → [ State + {error}]] . Из приведенных соотношений следует, что вычисление значения команды языка программирования SMalL приводит, вообще говоря, к изменению состояния, причем возможно возникновение ситуации (например, несоответствия типов в ходе присваивания), при которой вырабатывается ошибка.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Семантика подмножества SML (4) Семантические предложения для денотатов выражений (начало, окончание см. след. слайд): E [0]s = (0,s); E [1]s = (1,s); E [true]s = (true,s); E [false]s = (false,s); E [I]s = (m, I = unbound) error, → (m,I,s); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В соответствии с намеченной схемой рассуждений, перейдем к описанию семантических предложений, которые описывают значение конкретных денотатов (т.е. правильно построенных конструкций) языка SMalL. Рассмотрим семантические предложения для денотатов констант целочисленного типа языка SMalL: E [0] s = (0, s); E [1] s = (1, s); Как видно из приведенных соотношений, денотатами констант целочисленного типа являются значения этих констант (в форме упорядоченных пар вида «значение»«состояние»), причем смены состояния программы не происходит. Рассмотрим семантические предложения для денотатов констант логического типа языка SMalL: E [true] s = (true, s); E [false] s = (false, s); Как видно из приведенных соотношений, денотатами констант логического типа являются значения этих констант (в форме упорядоченных пар вида «значение»-«состояние»), причем смены состояния программы не происходит. Рассмотрим семантическое предложение для денотатов идентификаторов языка SMalL: E [I] s = (m, I = unbound) error, → (m, I, s). Как видно из приведенного соотношения, при возможности связывания денотатами идентификаторов являются идентификаторы, связанные со значениями (в форме упорядоченных троек вида «значение в памяти»-«идентификатор»-«состояние»), причем смены состояния программы не происходит, а при невозможности – выдается сообщение об ошибке.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Семантика подмножества SML (5) Семантические предложения для денотатов выражений (окончание): E[~E]s = (E[E]s=(v,s’))→ (isBool v→ (not v,s’), error, error; E[E1=E2]s = (E[E1]s=(v1,s1)) → (E[E2]s1=(v2,s2)) → (v1=v2 , s2), error), error; E[E1+E2]s = (E[E1]s=(v1,s1)) → (E[E2]s1=(v2,s2)) → (IsNum v1 and IsNum v2 → v1+v2,s2), error), error), error; Упражнение. Разработать семантические предложения для денотатов команд. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим семантические предложения для денотатов выражений языка SMalL: E [~E] s = (E [E] s=(v, s’)) (isBool → (not v, s’), error, error; E [E1=E2] s = (E [E1]s = (v1, s1)) → (E [E2] s1 = (v2, s2)) → (v1 = v2, s2), error), error; E [E1+E2] s = (E [E1] s=(v1, s1)) → (E [E2] s1 = (v2, s2)) → (IsNum v1 and IsNum v2 → v1 + v2, s2), error), error), error. Проанализируем полученные соотношения. Денотатом отрицания выражения является отрицание его значения; причем состояние программы изменяется. В случае несоответствия типов или небулевости выражения генерируется сообщение об ошибке. Денотатом присваивания является присвоенное значение в новом состоянии. В случае несоответствия типов генерируется сообщение об ошибке. Денотатом сложения присваивания является значение суммы в новом состоянии. В случае несоответствия типов генерируется сообщение об ошибке. В качестве упражнения предлагается самостоятельно разработать семантические предложения для денотатов команд языка программирования SMalL. Кратко резюмируем итоги лекции. В ходе лекции была представлена классификация подходов к семантике языков программирования, признан целесообразным денотационный подход, который проиллюстрирован на примере языка SMalL – ограниченного подмножества SML.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Библиография (1) 1. 2. 3. 4. 5.
Barendregt H.P. The lambda calculus (revised edition), Studies in Logic, 103, North Holland, Amsterdam, 1984 Scott D.S. Domains for denotational semantics. ICALP 1982, 577-613 Gordon M.J.C. The denotational description of programming languages. Springer-Verlag, 1979. Landin. P.J. The mechanical evaluation of expressions. Computer Journal, 6:308-320, January 1964. Hoare C.A.R. An axiomatic basis for computer programming. CACM 12(10):576-580, 1969 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду По итогам обсуждения можно сделать следующие выводы: 1) семантика языков функционального программирования достаточно близка к семантике формальных теорий, на которых они основаны (в частности, это справедливо для ламбда-исчисления и языка SML); 2) теория вычислений является актуальной и адекватной формализацией семантики; 3) денотационный подход является наиболее целесообразным для моделирования семантики языков программирования. К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать семантику языка программирования. Для более детального ознакомления с особенностями, достижениями и проблемами в области семантики рекомендуется следующий список литературы: 1. Barendregt H.P. The lambda calculus (revised edition), Studies in Logic, 103, North Holland, Amsterdam, 1984 2. Scott D.S. Domains for denotational semantics. ICALP 1982, 577-613 3. Gordon M.J.C. The denotational description of programming languages. Springer-Verlag, 1979. 4. Landin. P.J. The mechanical evaluation of expressions. Computer Journal, 6:308-320, January 1964. 5. Hoare C.A.R. An axiomatic basis for computer programming. CACM 12(10):576-580, 1969 Кратко остановимся на источниках. Работа [1] является энциклопедией ламбдаисчисления, основной формализации языков функционального программирования. В работах [2,3] рассматриваются вопросы, связанные с развитием денотационной семантики, и в частности, с ее представлением посредством доменов. Работа [4] содержит формализацию системы вычислений, основанной на состояниях. В работе [5] представлен вариант операторного подхода к семантике в форме аксиоматического метода.
Современные языки программирования и .NET: I семестр Лекция 8: Семантика языков программирования
Библиография (2) 1. 2. 3.
Floyd R.W. A note on mathematical induction on phrase structure grammars. Information and Control 4(4): 353-358, 1961 Gunter C.A., Scott D.S. Semantic Domains. Handbook on theoretical computer science, Vol.B: Formal models and semantics (B):633-674, 1990. Stoy J.E. Denotational semantics: the Scott-Strachey approach to programming language theory. MIT Press, 1977
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение работ, посвященных исследованию семантики. 1. Floyd R.W. A note on mathematical induction on phrase structure grammars. Information and Control 4(4): 353-358, 1961 2. Gunter C.A., Scott D.S. Semantic Domains. Handbook on theoretical computer science, Vol.B: Formal models and semantics (B):633-674, 1990. 3. Stoy J.E. Denotational semantics: the Scott-Strachey approach to programming language theory. MIT Press, 1977 В работе [1] излагается метод индуктивных утверждений, одно из математических оснований операционной семантики. В работах [2,3] рассматриваются вопросы, связанные с основами и развитием денотационной семантики, в частности, с ее формальными моделями и их приложением к реализации языков программирования.
Рекурсивные функции и множества
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к понятийному аппарату, истории развития, существующим подходам и выразительным возможностям рекурсивного представления функций и множеств в формальных теориях и языках программирования.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Содержание лекции 1. 2. 3. 4. 5. 6. 7.
Рекурсия в математике и программировании Рекурсивное определение типов данных и функций Коррекция понятия «множество» для формализации рекурсии: домены Неподвижная точка функции. Теорема о неподвижной точке Комбинатор Y как модель рекурсивной функции Примеры простейших рекурсивных функций на SML Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию рекурсивного представления типов, функций и множеств в формальных теориях и языках программирования. При этом будет предпринята попытка классификации существующих видов рекурсии. Далее будет представлено неформальное введение в наиболее адекватный целям данного курса и достаточно широко распространенный на сегодня подход к моделированию рекурсии, а именно, теорию неподвижных точек функций, формализованную с помощью комбинаторной логики. Теоретические рассуждения о рекурсии в формальных теориях (на примере комбинаторной логики и теории вычислений Д. Скотта) будут проиллюстрированы представлением основополагающих рекурсивных типов и функций языка программирования SML, включая функцию, неявно реализующую комбинатор неподвижной точки. При этом существенное внимание будет также уделено анализу границ практической применимости рекурсивного подхода к вычислениям, а также возможностей использования инструментальных средств .NET для реализации рекурсивных функций. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Важнейшие работы в области рекурсии 1936 – С. Клини (S.C. Kleene) доказал реализуемость рекурсии средствами ламбда-исчисления 1950-е – Х. Карри (Haskell .B. Curry) разработал комбинаторную логику как формальную систему с возможностью моделирования рекурсии 1960 – Дж. Maккарти (John McCarthy) исследовал практическую применимость рекурсивных вычислений для символьной обработки в ходе создания языка LISP 1969 – Д. Скотт (Dana S. Scott) предложил использовать домены (особый вид множеств) для формализации рекурсивно определенных функций и множеств
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко остановимся на наиболее значительных (с точки зрения данного курса) этапах эволюции теории и практики рекурсивных вычислений в формальных теориях и языках программирования. Принципиальная реализуемость рекурсии средствами математической теории была доказана С. Клини (S.C. Kleene) еще в 30-х г.г. При этом фундаментом рассуждений служило ламбда-исчисление. Значительно позже, уже в 50-х г.г., Х. Карри (Haskell B. Curry) была разработана комбинаторная логика как более приближенная к практике программирования формальная система с возможностью моделирования рекурсии. Вскоре, в 60-х г.г., Джоном Маккарти (John McCarthy) в ходе создания языка функционального программирования LISP, основанного на упомянутых выше теориях, была исследована практическая применимость рекурсивных вычислений для символьной обработки и доказана возможность реализации рекурсии в программировании. В конце 60-х г.г. Д. Скоттом (Dana S. Scott) было предложено использовать модель, основанную на доменах (которые можно понимать как особый вид множеств) для формализации рекурсивно определенных функций и множеств в рамках созданной исследователем теории вычислений.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Определение рекурсии Рекурсивное определение объекта (в математике и программировании) - это определение, которое содержит внутри себя ссылку на определяемый объект. Рекурсивно определенный объект (функция, множество или тип) называется рекурсивным. Для формализации рекурсивных функций и множеств используются комбинаторная логика и теории на основе доменов. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду После краткого введения в историю исследуемой области знаний, перейдем к неформальному обсуждению понятия рекурсии. Под рекурсивным определением объекта (как в абстрактном теоретическом смысле, так и в аспекте практического программирования) будем понимать такое определение, которое содержит внутри себя ссылку на определяемый объект. Основными видами объектов, которые будут использоваться в дальнейшем при рекурсивных вычислениях, будут следующие: 1) функция; 2) множество; 3) тип. Заметим, что рекурсивно определенный (т.е. построенный посредством рекурсии) объект, в свою очередь, носит название рекурсивного. Заметим также, что определение рекурсивных объектов в математике происходит по индукции. При этом сначала формулируется базис индукции, как рекурсивное определение исключительных случаев при построении типа или множества (или вычисления функции), а затем шаг индукции, как рекурсивное правило построения того же объекта. Для формализации рекурсивных функций и множеств в дальнейшем будут использоваться комбинаторная логика и теория вычислений Д. Скотта, основанная на понятии домена (последнее будет уточнено в ходе лекции).
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Примеры рекурсивных функций • факториал: fun fact n = if (n<2) 1 else n*fact(n-1) • длина списка : fun length lst = if (lst==[]) 0 else 1 + length(tl(lst)) • суммирование натуральных чисел от 1 до n: fun sumpos n = if (n<2) 1 else n + sumpos (n-1) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В качестве практической и наглядной иллюстрации определения понятия рекурсии, рассмотрим ряд показательных примеров рекурсивных функций, описанных на языке программирования SML. Начнем с описания известной нам функции факториала на языке SML: fun fact n = if (n<2) 1 else n*fact(n-1) Как следует из описания, значением функции является 1, если значение аргумента не превышает 1, и произведение чисел натурального ряда от 1 до заданного в противном случае. Заметим, что идентификатор функции fact явно присутствует как в левой, так и в правой части описания. Отметим также, что настоящий пример, по сути, представляет собой линейный вариант записи математического определения функции факториала по индукции. Наконец, еще одной особенностью рекурсии является многократность вызова одной и той же функции с различными значениями аргумента. Далее рассмотрим описание функции, которая вычисляет длину списка: fun length lst = if (lst==[]) 0 else 1 + length(tl(lst)) Заметим, что функция length использует встроенную функцию tl (получение «хвоста» списка) в ходе вычислений. Заметим также, что реализация рекурсивной обработки списка (который, кстати, является встроенным рекурсивным типом языка SML) выглядит лаконично и является весьма наглядной. Наконец, рассмотрим рекурсивное определение функции sumpos, суммирующей первые n чисел натурального ряда (и повторяющей отмеченные особенности функции fact): fun sumpos n = if (n<2) 1 else n + sumpos (n-1)
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Примеры рекурсивных определений типов (1) Список из элементов типа t либо пуст, либо состоит из головы и хвоста, где голова – элемент типа t, а хвост – список из элементов типа t. Бинарное дерево из элементов типа t либо пусто, либо состоит из корня и двух поддеревьев, где корень – элемент типа t, а каждое из поддеревьев является деревом. Замечание. Рекурсивные функции (подсчет количества элементов списка, обход дерева и т.д.) целесообразно использовать для рекурсивно определенных объектов. Упражнение. Построить математическое описание рекурсивной функции (факториала) и сравнить его с SML-кодом данной функции.
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе обсуждения примеров рекурсивного определения функций на программирования SML было упомянуто понятие рекурсивного типа для списков.
языке
Рассмотрим достаточно формальные определения важнейших рекурсивных типов, а именно, списка и дерева, выраженные в словесном виде. Прежде всего, приведем определение списка. Список из элементов типа t либо пуст, либо состоит из головы и хвоста, где голова – элемент типа t, а хвост – список из элементов типа t. Приведем определение дерева (для частного случая бинарного дерева). Бинарное дерево из элементов типа t либо пусто, либо состоит из корня и двух поддеревьев, где корень – элемент типа t, а каждое из поддеревьев является деревом. Подчеркнем, что оба приведенных определения являются рекурсивными определяемые понятия определяются c использованием самих этих понятий).
(т.е.
Отметим, что и список, и дерево имеют абстрактный (параметрический) тип аргументов, т.е. это, вообще говоря, полиморфные объекты. Именно таким образом список и дерево трактуются в языке программирования SML. Заметим также, что для манипулирования рекурсивно определенными объектами (в частности, списками и деревьями) целесообразно использовать рекурсивно определенные функции (например, подсчет количества элементов списка, обход дерева и т.д.). В качестве упражнения предлагается построить математическое описание по индукции для рекурсивной функции (скажем, факториала) и сравнить его с программой на языке SML, содержащей описание данной функции.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Примеры рекурсивных определений типов (2) Для задания рекурсивных типов в SML используются определения типов datatype следующего вида: <определение типа>:: = datatype <имя типа> = <описание типа>; где <описание типа>:: = <выражение> | (здесь “|” - символ SML) <имя элемента типа> of <конструктор> <конструктор> = <тип> * … * <тип> © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Изучив порядок определения рекурсивных функций в языке программирования SML, перейдем к определению рекурсивных типов. Для задания рекурсивных типов в SML используются определения типов datatype следующего вида: <определение типа>:: = datatype <имя типа> = <описание типа>; где <описание типа>:: = <выражение> | <имя элемента типа> of <конструктор> причем под конструктором понимается запись вида <конструктор> = <тип> * … * <тип> Заметим, что фигурирующий в описании рекурсивного типа символ “|” является частью алфавита языка программирования SML. Кроме того, обратим внимание на рекурсивный характер определения, который выражается в том, что типы в конструкторе могут совпадать с определяемым типом. Наконец, отметим, что значок «*», используемый в конструкторе типов SML, семантически аналогичен конструктору «×» для декартова произведения доменов.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Примеры рекурсивных определений типов (3) Примеры определения рекурсивных типов в SML: 1) список из целочисленных элементов: datatype intlist = nil | element of int * intlist; 2) бинарное дерево из целочисленных элементов: datatype inttree = empty | node of int * inttree * inttree; Замечание. Операция “|” конструирования типов в SML соответствует конструктору дизъюнктной суммы, а “*” – прямого произведения доменов. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем сказанное о рекурсивных определениях типов содержательными примерами на языке программирования SML. В частности (поскольку достаточно сложное понятие полиморфизма будет рассматриваться существенно позднее), рассмотрим описания списка и бинарного дерева с целочисленными элементами. Приведем описание списка из целочисленных элементов на языке SML: datatype intlist =
nil | element of int * intlist;
Приведем описание бинарного дерева из целочисленных элементов на языке SML: datatype inttree = empty | node of int * inttree * inttree; Заметим, что операция “|”, применяемая для конструирования типов в SML, соответствует конструктору дизъюнктной суммы «+», а операция “*”, как уже отмечалось – прямого произведения доменов «×».
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Определение комбинатора Переменная x называется свободной в терме λx.A, если она не имеет вхождений в терм A; в противном случае переменная x называется связанной Для составных термов связанность переменных определяется индукцией по построению. Терм, не содержащий свободных переменных, называется комбинатором. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как уже отмечалось, для формализации рекурсивных вычислений будет использоваться система комбинаторной логики. Напомним, что важнейшим понятием для любой формы комбинаторной логики является понятие комбинатора. Для того, чтобы формально определить комбинатор, необходимо ввести понятие свободной и связанной переменной в ламбда-выражении. Переменная x называется свободной в ламбда-выражении (терме) вида λx.A, если она не имеет вхождений в терм A; в противном случае переменная x называется связанной. Для составных ламбда-выражений понятие связанной и свободной переменной определяется индукцией по построению с учетом возможных способов комбинирования, а именно, операций аппликации и абстракции. Теперь становится возможным дать лаконичное определение комбинатора. Ламбда-выражение комбинатором.
(терм),
не
содержащее
свободных
переменных,
называется
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Комбинатор неподвижной точки Ни один из базисных комбинаторов K и S не может моделировать рекурсию. Предположим существование комбинатора Y, который при аппликации к любому комбинаторному терму (т.е. функции) E остается неизменным: Y E = E (Y E). Оказывается, что объект Y с такой характеристикой действительно существует, и его принято называть комбинатором неподвижной точки. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Попытаемся исследовать известные нам комбинаторы на предмет применимости для моделирования рекурсивных вычислений. Предположим существование комбинатора Y, который при аппликации к любому комбинаторному терму (т.е. функции) E остается неизменным: Y E = E (Y E). К сожалению, выясняется, что ни один из ранее рассмотренных нами комбинаторов (I) (K) (S) (B) (C) (W)
I a = a; К ab = a; S abc = ac(bc); B abc = a(bc); C abc = acb; W xy = xyy
не обеспечивает требуемой возможности. Тем не менее, оказывается, что объект Y с указанной выше характеристикой действительно существует и известен в литературе под названием комбинатора неподвижной точки.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Теорема о неподвижной точке Для любой функции f, представимой в ламбдаисчислении существует ламбда-терм Y, такой что он является неподвижной точкой функции f, т.е. выполняется соотношение Yf = f(Yf). При этом объект Y имеет конечный вид: Y = λf. (λx. f (x x)) (λx. f (x x)), или, в форме комбинаторной характеристики: Y = WS(BWB), где W=CSI, C=S(BBS)(KK), B=S(KS)K. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для получения характеристического соотношения, задающего комбинатор неподвижной точки, необходимо сформулировать (и доказать, что, впрочем, выходит за рамки данного курса) следующую теорему. Сформулируем теорему о неподвижной точке функции. Для любой функции f, представимой в ламбда-исчислении, существует ламбда-терм Y, такой что он является неподвижной точкой функции f, т.е. выполняется соотношение Yf = f(Yf). При этом объект Y имеет конечный вид: Y = λf. (λx. f (x x)) (λx. f (x x)), или, в форме комбинаторной характеристики: Y = WS (BWB), где W = CSI, C = S (BBS) (KK), B = S (KS) K. Таким образом, любая функция имеет «неподвижную точку» в форме комбинатора Y, характеристику которого можно явно представить в базисе комбинаторов {K, S}.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Неявная реализация комбинатора Y на SML Определим тип данных: datatype ‘a t = T of ‘a t -> ‘a; Определим функцию: val Y = fn f => (fn (T x) => (f (fn a => x (T x) a))) (T (fn (T x) => (f (fn a => x (T x) a)))); Реализация комбинатора Y посредством явной рекурсии (например, с помощью конструкций fun или let rec) является тривиальной задачей. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Исследуем возможность описания комбинатора неподвижной точки Y на языке программирования SML. Очевидно, что явным образом этот комбинатор реализован посредством рекурсивных определений функций с помощью рассмотренного нами варианта конструкции fun (или рекурсивного варианта подстановки let – конструкции let rec). Следовательно, реализация комбинатора Y посредством явной рекурсии является тривиальной задачей. Для решения поставленной задачи возьмем за основу приведенное на предыдущем слайде ламбда-выражение для комбинатора Y. Далее, определим следующий тип данных: datatype ‘a t = T of ‘a t -> ‘a; Теперь определим функцию: val Y = fn f => (fn (T x) => (f (fn a => x (T x) a))) (T (fn (T x) => (f (fn a => x (T x) a)))); Можно практически убедиться в том, что построенная таким образом (в полном соответствии с теорией) функция для комбинатора неподвижной точки Y действительно решает поставленную задачу.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Использование доменов для формализации семантики рекурсивных функций и множеств Денотационная семантика описывается уравнениями, задающими абстрактные функции на состояниях; переменные метаязыка пробегают по доменам. Домены требуют выполнения следующих дополнительных ограничений по сравнению с обычными множествами: 1) все рекурсивные определения разрешимы; 2) все домены имеют неопределенные элементы; 3) производные домены сохраняют структуру базовых ; 4) допустимы рекурсивные равенства между доменами. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим связь ставшего концептуально ясным и практически апробированным понятия рекурсии с теорией вычислений. Ранее уже упоминалось о том обстоятельстве, что домены в теории вычислений Д. Скотта используются для формализации семантики рекурсивно определенных функций и множеств. Напомним, что в исследованиях Д. Скотта речь идет о денотационной семантике языков программирования. Последняя описывается уравнениями, задающими абстрактные функции на состояниях. При этом вводится специализированный метаязык, в котором переменные пробегают по доменам. Ранее, говоря о доменах, мы ограничивались констатацией того утверждения, что домены представляют собой до некоторой степени аналог множеств в теоретико-математическом смысле. Кроме того, отмечалось то обстоятельство, что домены требуют выполнения определенных дополнительных ограничений по сравнению с обычными множествами. На данном этапе представляется возможным конкретизировать форму упомянутых ограничений. Итак, существуют следующие ограничения, которые отличают домены от множеств: 1) все рекурсивные определения являются разрешимыми; 2) все домены имеют неопределенные элементы, необходимые для «обработки исключительных ситуаций», как, например в случае с элементом unbound, характеризующим невозможность связывания переменной со значением, или элемента error, характеризующего общую ошибку; 3) производные (т.е. построенные с помощью ранее исследованных в курсе конструкторов) домены сохраняют структуру базовых; 4) между доменами допускаются не только непосредственные, но и рекурсивные равенства.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Виды рекурсии Различают несколько видов рекурсии, основные из которых сводятся к следующим: 1) прямая рекурсия (простейший тип рекурсии, рассмотренный ранее); 2) взаимная рекурсия (функция f определяется через функцию g и наоборот); 3) частичная рекурсия (рекурсивная функция является частично определенной). Все перечисленные виды рекурсии адекватно формализуются теорией вычислений Д.Скотта, ламбда-исчислением и комбинаторной логикой. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В настоящей лекции мы ограничились рассмотрением простейшего вида рекурсии. Однако, существует еще несколько видов рекурсивных определений объектов (в частности, функций), рассмотрение которых может представить теоретический интерес и практическую важность. Кратко перечислим основные виды рекурсии. Во-первых, отметим, что тот простейший тип рекурсии, который рассматривался ранее, носит название прямой рекурсии. Более сложным видом рекурсивных определений является так называемая взаимная рекурсия. В таком случае, скажем, при формулировке рекурсивного определения функции, функция f определяется через функцию g и наоборот. Еще одним важным типом рекурсии является рекурсия, известная под названием частичной. В случае задания описания, скажем, функции, с помощью частичной рекурсии, вновь вводимая функция является частично определенной. Заметим в заключение, что все перечисленные выше виды рекурсии адекватно формализуются посредством теории вычислений Д. Скотта, а также формализаций, основанных на ламбда-исчислении и комбинаторной логике.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Преимущества .NET для реализации рекурсии 1) интегрированная среда гетерогенных языков программирования позволяет сократить сроки реализации сложных (требующих рекурсивных и нерекурсивных функций) проектов; 2) широкий спектр унифицированных предопределенных структур данных (списки, деревья, очереди и т.д.) позволяет увеличить эффективность реализации и повторно использовать код; 3) рекурсия лучше соответствует ориентированным на обработку рекурсивных структур данных языкам функционального программирования (SML, Haskell, Scheme и др.). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подводя итоги обсуждения рекурсивного определения функций, типов и множеств, выделим наиболее значимые результаты. Во-первых, рекурсия относится к достаточно хорошо изученным областям computer science и имеет целый ряд вполне адекватных формализаций, наиболее важными из которых являются комбинаторная логика и теория вычислений Д. Скотта. Во-вторых, рекурсивные вычисления концептуально ясно и интуитивно прозрачно реализуемы посредством функционального подхода к программированию. В-третьих, платой за лаконичность и прозрачность (с математической точки зрения) реализации рекурсий является необходимость (многократного) повторного вычисления функций. Поскольку наше исследование языков программирования базируется на технологическом фундаменте .NET, перечислим основные результаты влияния данной платформы на реализацию рекурсии: 1) интегрированная среда гетерогенных языков программирования позволяет сократить сроки реализации сложных (требующих рекурсивных и нерекурсивных функций) проектов; 2) широкий спектр унифицированных предопределенных структур данных (списки, деревья, очереди и т.д.) позволяет увеличить эффективность реализации и повторно использовать код; 3) рекурсия лучше соответствует ориентированным на обработку рекурсивных структур данных языкам функционального программирования (SML, Haskell, Scheme и др.).
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Библиография (1) 1.
Kleene S.C. λ-definability and recursiveness. Duke Math. J., pp. 340-353, 1936
2.
McCarthy J. Recursive functions of symbolic expressions and their computation by machine, Part I. Com. ACM, April 1960
3.
Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958
4.
Scott D.S. Domains for denotational semantics. ICALP 1982, 577-613 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать рекурсивные вычисления. Для более детального ознакомления с особенностями, достижениями и проблемами в области исследований рекурсии рекомендуется следующий список литературы: 1. Kleene S.C. λ-definability and recursiveness. Duke Math. J., pp. 340-353, 1936 2. McCarthy J. Recursive functions of symbolic expressions and their computation by machine, Part I. Com. ACM, April 1960 3. Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 4. Scott D.S. Domains for denotational semantics. ICALP 1982, 577-613 Кратко остановимся на источниках. Работа [1] является новаторской в области моделирования рекурсии посредством ламбда-исчисления. В работе [2] рассматриваются вопросы, связанные с практической реализацией рекурсии в языках функционального программирования. Работа [3] содержит описание системы комбинаторной логики, основной формализации неподвижных точек функций. В работе [4] представлена теория семантических доменов, одного из способов формализации рекурсивно определенных множеств.
Современные языки программирования и .NET: I семестр Лекция 9: Рекурсивные функции и множества
Библиография (2) 5.
Hindley J.R., Seldin J.P. Introduction to combinators and λcalculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986
6.
Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение работ, посвященных исследованию рекурсии. 5. Hindley J.R., Seldin J.P. Introduction to combinators and l-calculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986 6. Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 В работе [5] излагается взаимосвязь фундаментальных теорий, формализующих рекурсивные вычисления. В работе [6] рассматриваются вопросы, связанные с приложением рекурсивных вычислений к реализации языков программирования.
Абстрактные машины и категориальная комбинаторная логика
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к понятийному аппарату, истории развития, существующим подходам в реализации и выразительным возможностям абстрактных машин.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Содержание лекции 1. 2. 3. 4. 5. 6. 7.
Понятие абстрактной машины Примеры идеальных абстрактных машин Абстрактные машины на состояниях SECD-машина П. Лендина Категориальная комбинаторная логика Категориальная абстрактная машина (КАМ) Библиография
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию вычислительных машин в формальных теориях, поддерживающих языки программирования. При этом будет предпринята попытка классификации существующих видов абстрактных машин. Далее будет представлено неформальное введение в наиболее адекватный целям данного курса и достаточно широко распространенный на сегодня подход к моделированию абстрактных машин, а именно, формальную систему категориальной комбинаторной логики. При этом существенное внимание будет уделено анализу границ практической применимости формальной системы категориальной комбинаторной логики для моделирования различных классов абстрактных машин. Формальное введение в категориальную комбинаторную логику предваряет изучение категориальной абстрактной машины, являющейся одной из фундаментальных формализаций, поддерживающих языки функционального программирования, и, в особенности, SML. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Важнейшие работы в области абстрактных вычислительных машин (1) 1936 – А.Тьюрингом (Alan Mathison Turing) и Э. Постом (Emil Leon Post) независимо друг от друга созданы эквивалентные по возможностям, но нереализуемые практически абстрактные машины (модели компьютера), потенциально реализующие произвольный алгоритм 1960-е – П. Лендин (Peter J. Landin) разработал SECDмашину – математическую формализацию для вычисления ламбда-термов, а также язык ISWIM (If you See What I Mean), ставший прообразом языка ML © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко остановимся на наиболее значительных (с точки зрения данного курса) этапах эволюции теории и практики абстрактных и виртуальных машин в формальных теориях и языках программирования. Еще задолго до появления высокоуровневых языков программирования, а именно, в 30-х г.г., А. Тьюрингом (Alan Mathison Turing) и Э. Постом (Emil Leon Post) независимо друг от друга созданы эквивалентные по возможностям, но практически весьма сложные в реализации формализации, известные как абстрактные машины и получившие названия по именам своих авторов. Абстрактные машины можно понимать как математические формализации, моделирующие компьютер, который имеет потенциальную возможность реализации произвольной последовательности элементарных операций, или алгоритма. Таким образом, создатели первых абстрактных машин, по сути, непосредственно предвосхитили появление языков программирования, создав пусть примитивные, но в полной мере алгоритмические императивные языки. Значительно позднее, в 60-х г.г., уже в эпоху высокоуровневых языков программирования, П. Лендином (Peter J. Landin) была разработана так называемая SECD-машина, а именно, математическая формализация для вычисления ламбдавыражений. Кроме того, тем же автором был создан формальный язык ISWIM (If you See What I Mean), представляющий собой вариант расширенного ламбда-исчисления и ставший впоследствии прообразом языка программирования ML, который, в свою очередь, эволюционировал в исследуемый нами язык программирования SML.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Важнейшие работы в области абстрактных вычислительных машин (2) 1975 – Г.Плоткин (G.D. Plotkin) развил исследования SECDмашины и применил результаты для моделирования ранних версий языка программирования ML 1980-е – П.-Л. Кюрьен, (Pierre-Louis Curien), Г. Кузино (Guy Cousineau) и М. Мони (Michel Mauny) с группой французских ученых создали категориальную абстрактную машину (КАМ) как развитие SECD-машины 1980-е – группа Кюрьена-Кузино-Мони реализует на основе КАМ в полном объеме диалект CaML языка ML © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду С появлением первой абстрактной машины, значительно более близкой по природе к высокоуровневым языкам программирования, чем ранние, наивные формализации Тьюринга и Поста, исследователями стали предприниматься попытки использования виртуальных машин для моделирования реальных языков программиирования. Так, в 70-х г.г. Г. Плоткиным (G.D. Plotkin) были проведены расширенные исследования SECD-машины, созданной П. Лендиным, и результаты удалось использовать для моделирования ранних версий реального языка функционального программирования ML. Затем, в 80-х г.г., группой французских ученых в составе П.-Л. Кюрьена, (Pierre-Louis Curien), Г. Кузино (Guy Cousineau), М. Мони (Michel Mauny) и ряда других исследователей удалось усовершенствовать формализацию SECD-машины и создать на ее основе так называемую категориальную абстрактную машину, или, сокращенно, КАМ, изучение которой и будет составлять предмет нашего дальнейшего рассмотрения на протяжении ближайших лекций. Наконец, в середине 80-х г.г. тем же авторским коллективом на основе категориальной абстрактной машины была создана полномасштабная реализация специально разработанного для этих целей диалекта языка функционального программирования ML, получившего (по имени абстрактной машины) название CaML.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Понятие абстрактной машины Абстрактной машиной называется математическая формализация, моделирующая правила выполнения программы для вычислительной машины. Абстрактные машины используются при реализации языков программирования как средство создания промежуточного кода (аналога p-кода, Java-кода, MSILкода), который затем транслируется в машинный код. Абстрактные машины позволяют моделировать рекурсию и различные стратегии вычислений. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду После краткого введения в историю исследуемой области знаний, перейдем к более формальному обсуждению понятия абстрактной машины. Абстрактной машиной (abstract machine) в рамках данного курса будем называть математическую формализацию, которая моделирует правила выполнения программы (или, иначе, алгоритмы) для той или иной реальной вычислительной машины (компьютера). В настоящее время при практической реализации различных классов языков программирования, в частности, функциональных и объектно-ориентированных языков, широко используются аналоги абстрактных машин в форме так называемых виртуальных машин (virtual machine). Виртуальные машины представляют собой средство создания промежуточного (следующего за текстом программы на высокоуровневом языке программирования) кода (именуемого в различных реализациях p-кодом, Java-кодом, MSIL-кодом и т.д.), который затем транслируется в машинный код. Заметим, что последний пример промежуточного кода, а именно, MSIL (Microsoft Intermediate Language), представляет собой ни что иное, как код промежуточный виртуальной машины, реализованной корпорацией Microsoft для технологической платформы .NET. Отметим также то обстоятельство, что абстрактные машины позволяют адекватно моделировать различные подходы и стратегии вычислений, включая ранее рассмотренные рекурсивные вычисления, а также вычисления по необходимости (иначе известные как «ленивые»), которые будут рассмотрены в продолжение курса.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Примеры абстрактных машин 1. • •
Ранние формализации на состояниях: машина Тьюринга (бесконечная лента, головка для чтения/записи информации); машина Поста (аналог машины Тьюринга);
2. Зрелые формализации на состояниях: • SECD-машина П. Лендина; • Категориальная машина (П.-Л. Кюрьен и др.) 3.
Другие формализации
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Уточнив понятия об абстрактных и виртуальных машинах, перейдем к исследованию особенностей различных классов рассматриваемых формализаций, проиллюстрировав выделенные классы необходимыми примерами из математической теории и практики программирования. Прежде всего, следует отметить то обстоятельство, что практически все без исключения абстрактные модели вычислительных машин оперируют понятием состояния, изменения которого и отражают ход выполнения программы. При этом следует, во-первых, выделить ранние, «наивные» формализации на состояниях, которые не были практически поддержаны ни языками программирования, ни собственно компьютерами. К ранним абстрактным машинам можно отнести известные из истории математики и уже упомянутые ранее машины Тьюринга и Поста. Первая абстрактная машина характеризовалась бесконечной лентой для хранения «инструкций», а также считывающей и записывающей головкой, передвигающейся по ленте; вторая машина действовала аналогично первой. Несмотря на объективные трудности практической реализации, представляющей в большей степени теоретический интерес, ранние абстрактные машины, безусловно, были весьма значимыми для развития computer science, т.к. предвосхитили появление и обозначили ряд этапов развития реальных компьютеров и языков программирования для них. Кроме того, следует отдельно рассмотреть боле поздние, зрелые формализации машин, основанные на состояниях. К ним в первую очередь относятся упомянутая ранее SECDмашина П. Лендина, а также категориальная абстрактная машина, к рассмотрению которых мы и переходим.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
SECD-машина П. Лендина Классическая АМ для редукции λ-термов с использованием вызова по значению (call-by-value). • • • •
Название получила от аббревиатур своих элементов: Stack – стек (последовательность атомов и λ-абстракций); Environment – среда (хранилище значений переменных); Сontrol – управление (последовательность инструкций); Dump – дамп (пуст либо содержит прежнее состояние). Именно эта четверка элементов определяет состояние. SECD-машина явилась прообразом для более поздних формализаций, на которых реализованы ML-машины. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как уже отмечалось, в 60-х г.г., уже в эпоху высокоуровневых языков программирования, П. Лендином (Peter J. Landin) была разработана так называемая SECD-машина, а именно, математическая формализация для вычисления ламбда-выражений. При этом, SECD-машина была предназначена для редукции лабмбда-выражений и использовала механизм передачи параметров при вызове функции по значению (call-byvalue), в отличие от других типов передачи параметра (например, по имени или call-byname). Свое название SECD-машина получила от аббревиатур имен своих основных четырех элементов, а именно: • • • •
Stack – стек, т.е. последовательность атомарных ламбда-выражений (переменных и констант), а также ламбда-абстракций; Environment – среда, т.е. хранилище значений, которые связываются с переменными в ходе вычислений; Control – управление, т.е. последовательность «инструкций», управляющих работой SECD-машины; Dump – дамп, т.е. хранилище состояния SECD-машины (обычно пуст либо содержит прежнее состояние).
Именно перечисленная четверка элементов в полной мере характеризует состояние SECDмашины в произвольный момент вычислений. Заметим, что именно SECD-машина явилась прообразом для более поздних формализаций, на которых реализованы ML-машины, в частности, категориальная абстрактная машина.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
КАМ: введение в теорию категорий (1)
1) 2) 3) 4) 5) 6) 7)
Название КАМ получила потому, что ее состояния принадлежат пространству декартово замкнутых категорий (д.з.к.), т.е. выполнены условия: определена функция тождества; определена операция композиции; определена операция образования упорядоченной пары объектов <•,•>; определена операция взятия первого элемента пары; определена операция взятия второго элемента пары; определена операция преобразования терма из алгебраической формы в аппликативную; определена операция применения функции к аргументу.
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перейдем к обсуждению теоретического фундамента, на котором основана категориальная абстрактная машина, а именно, к формальной системе категориальной комбинаторной логики. Как уже отмечалось, своим названием категориальная абстрактная машина обязана тому обстоятельству, что множество ее возможных состояний принадлежит пространству так называемых декартово замкнутых категорий (или, сокращенно, д.з.к.). Формальная система с декартово замкнутыми категориями должна удовлетворять следующим условиям: 1) определена функция тождества, или тождественное преобразование (имеющее в комбинаторной логике аналог в форме комбинатора тождества I); 2) определена операция композиции или построения сложной функции (имеющая в комбинаторной логике аналог в форме комбинатора тождества B); 3) определена операция образования упорядоченной пары объектов <·,·>; 4) определена операция взятия первого элемента из упорядоченной пары объектов; 5) определена операция взятия второго элемента из упорядоченной пары объектов; 6) определена операция преобразования терма из алгебраической формы в аппликативную; 7) определена операция аппликации или применения функции к аргументу.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
КАМ: введение в теорию категорий (2) Условия (1) и (2) необходимы для формирования категорий, (3)-(5) – для декартовых категорий, а (6) и (7) – для д.з.к. Для декартовых категорий необходимо дополнительно потребовать существования функционального пространства или операции экспоненцирования. Операция, требуемая условием (6), называется каррированием, а обратная ей – декаррированием.
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проанализируем смысл сформулированных условий для категорий. Условия существования тождественного преобразования и построения сложных функций являются основополагающими и необходимы для формирования категорий произвольного типа. Условия существования операции образования упорядоченной пары объектов, а также операций взятия первого и второго элемента из упорядоченной пары необходимы для построения декартовых категорий, т.е. категорий, оснащенных операцией прямого (или, иначе, декартова) произведения и соответствующих ему проекций. Наконец, условия существования операций аппликации и преобразования терма из алгебраической формы в аппликативную являются необходимыми для формирования категорий произвольного декартово замкнутых категорий. Заметим, что последняя операция называется каррированием, а обратная ей – декаррированием по имени основоположника комбинаторной логики Х. Карри (Haskell B. Curry). Кроме перечисленных выше условий, для построения декартовых категорий необходимо дополнительно потребовать существования функционального пространства или операции экспоненцирования.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Категориальная комбинаторная логика (1) Добавим к известным нам комбинаторам I, K, S, B, C следующие «машинные инструкции»-комбинаторы: D = λxy.[x,y] = λxyr.rxy; S = CIS; Λ = λx.(λz.x[y,z]); ‘ = K = λx.(λy.x).
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для реализации категориального расширения комбинаторной логики (известного также под названием категориальной комбинаторной логики, или, сокращенно, ККЛ), добавим к известным нам комбинаторам (I) (K) (S) (B) (C)
I a = a; К a b = a; S a b c = a c (b c); B a b c = a (b c); Cabc=acb
следующие комбинаторы, выступающие в роли «машинных инструкций» категориальной абстрактной машины: (D) (S) (Λ) (‘)
D = λ x y . [x, y] = λ x y r . r x y; S = C I S; Λ = λ x . (λ z . x [y, z]); ‘ = K = λ x . (λ y . x).
Заметим, что характеристическое соотношение (D) представляет собой операцию образования упорядоченной пары, соотношение (Λ) – каррирование, а соотношение (‘), ранее известное нам как характеристика комбинатора-канцелятора K – операцию взятия первой проекции для упорядоченной пары элементов, которую можно также понимать как цитирование.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Категориальная комбинаторная логика (2) Кроме того, добавим бесконечное множество комбинаторов n! со следующими семантическими характеристиками (||•|| – функция вычисления значения): ||n|| = n! (значение числа); ||с|| = ‘с (значение константы); ||M,N|| = S[||M||,||N||] (значение пары); || λx.M|| = Λ (M) (значение абстракции). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим построение формальной системы категориальной комбинаторной логики. Рассмотрим семантический аспект данной системы, основываясь на функции вычисления значения выражения категориальной комбинаторной логики, соотнесенной, вообще говоря, с той или иной средой. Введем одноместную функцию вычисления значения выражения для произвольного выражения, которую обозначим как ||·||. Скажем, значение терма M в таком случае будет иметь вид || M ||. Далее добавим бесконечное множество комбинаторов n! со следующей семантической характеристикой: ||n|| = n!. Продолжим семантические равенства следующим соотношением, характеризующим значения констант: ||с|| = ‘с. Как следует из приведенного соотношения, для вычисления значения константы используется комбинатор цитирования (что хорошо согласуется с практикой, принятой в языках функционального программирования, в частности, в языке LISP). Значения упорядоченной пары и ламбда-абстракции, как оказывается, задаются с помощью ранее рассмотренных комбинаторов S и Λ: ||M,N|| = S [||M||,||N||]; || λx.M|| = Λ (M).
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Категориальная комбинаторная логика (3) Благодаря введению дополнительных комбинаторов D, S, ‘ и Λ вышеперечисленные синтактико-семантические соотношения сводимы к чисто синтаксическим: 0![x,y] = y; (n+1)![x,y] = n! x; S[x,y]z = xz(yz) (декаррирование); Λ (x) yz = x[y,z] (каррирование). Последние два соотношения необходимы для перехода к категориальной комбинаторной логике (ККЛ). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим построение формальной системы категориальной комбинаторной логики. Заметим, что благодаря введению в рассмотрение дополнительных комбинаторов (D) (S) (Λ) (‘)
D = λ x y . [x, y] = λ x y r . r x y; S = C I S; Λ = λ x . (λ z . x [y, z]); ‘ = K = λ x . (λ y . x)
вышеперечисленные синтактико-семантические соотношения синтаксическим равенствам, которые имеют следующий вид:
сводимы
к
чисто
0 ! [x, y] = y; (n + 1) ! [x, y] = n! x; S [x, y] z = x z (y z); Λ (x) y z = x [y, z]. Отметим, что последние два соотношения, означающие соответственно декаррирование и каррирование, необходимы для завершения перехода от формальной системы комбинаторной логики (или, сокращенно, КЛ) к формальной системе категориальной комбинаторной логики (или, сокращенно, ККЛ).
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Категориальная комбинаторная логика (4) Введем комбинатор образования пары <•,•> = λt.[•t, •t] с комбинаторной характеристикой = λt. λz. (f t)(g t) = λt.[f t, g t] и соответствующим семантическим равенством ||M,N|| = <||[M]||, ||[N]||>. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим построение формальной системы категориальной комбинаторной логики. Для того, чтобы формализация приняла более строгий и удобный вид, необходимо ввести в рассмотрение двухместный комбинатор образования пары, который определяется ламбда-выражением следующего вида: <·, ·> = λ t. [·t, ·t]. При этом комбинаторная характеристика вновь введенного комбинатора образования пары имеет следующий вид: = λt. λz. (f t)(g t) = λt.[f t, g t]. Кроме того, комбинатор образования пары характеризуется следующим семантическим равенством: ||M, N|| = <||[M]||, ||[N]||>.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Категориальная комбинаторная логика (5) Оснастим декартово произведение проекциями Fst = C I K = (n+1)!
и
Snd = C I (K I) = (0)!
с характеристическими соотношениями Fst [x, y] = x
(первая проекция);
Snd [x, y] = y
(вторая проекция);
<x, y> z = [x z, y z]
(пара функций).
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим построение формальной системы категориальной комбинаторной логики. После задания операции образования упорядоченной пары функций, для завершения формализации операции прямого или декартова произведения необходимо определить операции взятия первого и второго элементов упорядоченной пары, или первой и второй проекций. Согласно общепринятой алгебраической практике, оснастим вновь введенную операцию декартова произведения комбинаторами первой и второй проекций с комбинаторными характеристиками следующего вида: Fst = C I K = (n+1)! Snd = C I (K I) = (0)! Отметим, что вновь введенные комбинаторы Fst для первой проекции и Snd для второй проекции имеют следующие характеристические соотношения: Fst [x, y] = x; Snd [x, y] = y; <x, y> z = [x z, y z]. Последнее соотношение определяет связь между комбинатором образования упорядоченной пары и так называемой парой функций, т.е. такой функцией, которая в результате дает совокупность результатов своих функций-компонентов x : A→B и y : A→C в виде функции w : A→B×C.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Категориальная комбинаторная логика (6) Избыточность комбинаторов Fst, Snd, (n+1)!, 0!, S, Λ устраняется введением комбинатора композиции o ≡ B. Введем явно комбинатор аппликации ε. Выведем соотношения, позволяющие устранить избыточные комбинаторы: (i)
S (x y t) = x t (y t) = ε [x t, y t] = (ε o <x, y>) t, отсюда S = λ x y. (ε o <x, y>).
Положим Fstn+1 = Fst o Fstn, для n>1 и Fst1 = Fst. Тогда (ii) n! = Snd o Fstn, для n>0, а 0! = Snd. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим построение формальной системы категориальной комбинаторной логики. Заметим, что введенная система комбинаторов Fst, Snd, (n+1)!, 0!, S, Λ является избыточной. Избыточность системы комбинаторов устраняется введением комбинатора композиции o ≡ B,
который принимается композиции B.
тождественно
равным
ранее
определенному
комбинатору
Далее, введем явно комбинатор аппликации ε. Выведем соотношения, комбинаторов:
которые
позволят
устранить
избыточность
S (x y t) = x t (y t) = ε [x t, y t] = (ε o <x, y>) t. Отсюда, (i)
S = λ x y. (ε o <x, y>).
Положим Fstn+1 = Fst o Fst n, для n > 1 и Fst1 = Fst. Тогда получим, что (ii)
n! = Snd o Fst n, для n > 0, а 0! = Snd.
системы
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Категориальная комбинаторная логика (7) Окончательный перечень характеристических равенств: (ass) (fst) (snd) (dpair) (ac) (quote)
(x o y) z = x (y z); Fst [x, y] = x; Snd [x, y] = y; <x, y> z = [x z, y z]; ε [Λ (x) y, z] = x [y, z]; (‘ x) y = x,
где (ass) устанавливает связь аппликации и композиции, (dpair) – спаривания и формирования совокупности. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Завершим построение формальной системы категориальной комбинаторной логики. С учетом устранения избыточных комбинаторов из рассматриваемой формальной системы, получим окончательный перечень характеристических соотношений категориальной комбинаторной логики: (ass)
(x o y) z = x (y z);
(fst)
Fst [x, y] = x;
(snd)
Snd [x, y] = y;
(dpair)
<x, y> z = [x z, y z];
(ac)
ε [Λ (x) y, z] = x [y, z];
(quote)
(‘ x) y = x.
Заметим, что соотношение (ass) устанавливает связь аппликации и композиции, соотношение (dpair) – спаривания и формирования совокупности, а соотношение (ac) – каррирования и апплицирования. Напомним, что соотношения (fst) и (snd) характеризуют операции взятия первой и второй проекций для упорядоченной пары объектов, а (quote) – цитирование. Приведенные соотношения (ass), (fst), (snd), (dpair), (ac) и (quote) адекватно (полно и непротиворечиво) формализуют систему категориальной комбинаторной логики.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Библиография (1) 1. 2. 3. 4.
Turing A.M. On computable numbers, with an application to the Entscheidungsproblem. Proc. of London Mathematical Society, ser .2, vol. 42 p.p. 230-265, 1936-7 Hodges A. Alan Turing and the Turing machine. The universal Turing machine: a half-century survey, pp. 3-15, New York, 1988 M. Davis (ed.) Solvability, probability, definability: the collected works of Emil L. Post, Boston, Massachusetts, 1994 Landin P.J. The next 700 programming languages. CACM, 9, pp. 157-164, 1966 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать абстрактные машины. Для более детального ознакомления с особенностями, достижениями и проблемами в области исследований абстрактных машин рекомендуется следующий список литературы: 1. Turing A.M. On computable numbers, with an application to the Entscheidungsproblem. Proc. of London Mathematical Society, ser .2, vol. 42 p.p. 230-265, 1936-7. 2.Hodges A. Alan Turing and the Turing machine. The universal Turing machine: a half-century survey, pp. 3-15, New York, 1988. 3. Davis M. (ed.) Solvability, probability, definability: the collected works of Emil L. Post, Boston, Massachusetts, 1994. 4. Landin P.J. The next 700 programming languages. CACM, 9, pp. 157-164, 1966. Кратко остановимся на источниках. Работы [1-3] посвящены ранним исследованиям в области абстрактных машин. В работе [4] рассматриваются вопросы, связанные с первой практической реализацией абстрактной машины применительно к языкам программирования.
Современные языки программирования и .NET: I семестр Лекция 10: Абстрактные машины и ККЛ
Библиография (2) 5. 6. 7.
8.
Plotkin G.D. Call-by-name, call-by-value and the λ-calculus. Theoretical computer science, 1, pp. 125-159, 1936 Cousineau G., Curien P.-L., Mauny M. The categorical abstract machine. Science of Computer Programming 8(2): 173-202, 1987 Mauny M., Suárez A. Implementing functional languages in the categorical abstract machine. Proc. of the 1986 ACM conference on LISP and functional programming, pp. 266278, Cambridge, Massachusetts, 1986 Peyton Jones S.L. The implementation of functional programming languages. Prentice Hall, 1987 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение работ, посвященных исследованию абстрактных машин. Приведем окончание библиографического списка. 5. Plotkin G.D. Call-by-name, call-by-value and the λ-calculus. Theoretical computer science, 1, pp. 125-159, 1936 6. Cousineau G., Curien P.-L., Mauny M. The categorical abstract machine. Science of Computer Programming 8(2): 173-202, 1987. 7. Mauny M., Suárez A. Implementing functional languages in the categorical abstract machine. Proc. of the 1986 ACM conference on LISP and functional programming, pp. 266-278, Cambridge, Massachusetts, 1986. 8. Peyton Jones S.L. The implementation of functional programming languages. Prentice Hall, 1987. В работе [5] излагается взаимосвязь различных стратегий вычисления в зависимости от типа вызова функции. Работы [6,7] содержат описание категориальной абстрактной машины. В работе [8] рассматриваются вопросы, связанные с реализацией современных языков функционального программирования.
Категориальная абстрактная машина
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к технике построения и выразительным возможностям такой формализации языков программирования как категориальной абстрактной машины.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Содержание лекции 1. 2. 3. 4. 5. 6. 7.
Процедура трансляции функциональной программы в КАМ-код Кодирование ламбда-термов по де Брейну Трансляция кода де Брейна в термы категориальной комбинаторной логики Синтаксис и семантика языка инструкций КАМ Цикл работы КАМ Сравнение КАМ с виртуальной машиной в .NET Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции будет рассмотрена формализация процедуры преобразования текста программы на языке функционального программирования в код категориальной абстрактной машины. При этом фактически будет предпринята попытка моделирования процедуры работы транслятора для того или иного языка программирования. Схема процедуры трансляции является многоэтапной и включает следующие стадии: 1) преобразование текста программы на языке функционального программирования в выражение ламбда-исчисления; 2) преобразование полученного выражения ламбда-исчисления в так называемый (промежуточный) код де Брейна (de Brujin); 3) преобразование полученного кода де Брейна в терм категориальной комбинаторной логики; 4) преобразование полученного терма категориальной комбинаторной логики в последовательность инструкций категориальной абстрактной машины; 5) выполнение результирующей последовательности инструкций категориальной абстрактной машины с означиванием в среде вычислений. При этом существенное внимание будет уделено анализу синтаксических семантических особенностей инструкций категориальной абстрактной машины.
и
Формальное исследование логики и процедуры смены состояний (или, иначе, цикла работы) категориальной абстрактной машины позволит провести сравнительный анализ возможностей КАМ и виртуальной машины, применяемой в технологической платформе .NET. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Постановка задачи
1) 2)
Требуется построить вариант комбинаторной логики для моделирования семантики вычислений на языке программирования с помощью функции вычисления значения. При этом существенно используются: условия для декартово замкнутых категорий (д.з.к.); характеристические равенства, определяющие поведение операторов, задающих денотационную семантику языка функционального программирования. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Исходя из представленных тем для обсуждения, произведем детализацию постановки задачи. Итак, требуется построить вариант формальной системы комбинаторной логики для моделирования семантики вычислений. Под вычислениями будем понимать трансляцию конструкций, которые заданы на языке программирования, в код категориальной абстрактной машины (возможно, с использованием некоторого промежуточного кода) с последующим означиванием результирующего кода в той или иной среде. Означивание кода категориальной абстрактной машины производится с помощью функции вычисления значения. При такой постановке задачи необходимо принять во внимание ряд ранее сформулированных условий, в частности: 1) условия, необходимые для построения формальной системы декартово замкнутых категорий (или, сокращенно, д.з.к.), рассмотренные нами в ходе предыдущей лекции; 2) характеристические равенства, которые определяют поведение операторов, задающих денотационную семантику языка функционального программирования, в том числе и инструкций категориальной абстрактной машины.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Условия для категорий 1) 2) 3) 4) 5) 6) 7)
Состояния КАМ должны принадлежать пространству д.з.к., т.е. должны выполняться условия: определена функция тождества; определена операция композиции; определена операция образования упорядоченной пары объектов <•,•>; определена операция взятия первого элемента пары; определена операция взятия второго элемента пары; определена операция преобразования терма из алгебраической формы в аппликативную; определена операция применения функции к аргументу. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним условия, необходимые для построения формальной системы декартово замкнутых категорий (или, сокращенно, д.з.к.), рассмотренные нами в ходе предыдущей лекции. Формальная система с декартово замкнутыми категориями должна удовлетворять следующим условиям: 1) определена функция тождества, или тождественное преобразование (имеющее в комбинаторной логике аналог в форме комбинатора тождества I); 2) определена операция композиции или построения сложной функции (имеющая в комбинаторной логике аналог в форме комбинатора тождества B); 3) определена операция образования упорядоченной пары объектов <·,·>; 4) определена операция взятия первого элемента из упорядоченной пары объектов; 5) определена операция взятия второго элемента из упорядоченной пары объектов; 6) определена операция преобразования терма из алгебраической формы в аппликативную; 7) определена операция аппликации или применения функции к аргументу. Заметим, что выполнение перечисленных условий необходимо для того, чтобы обеспечить принадлежность состояний категориальной абстрактной машины пространству декартово замкнутых категорий.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Характеристические равенства Напомним перечень характеристических равенств для инструкций КАМ: (ass) (fst) (snd) (dpair) (ac) (quote)
(x o y) z = x (y z); Fst [x, y] = x; Snd [x, y] = y; <x, y> z = [x z, y z]; ε [Λ (x) y, z] = x [y, z]; (‘ x) y = x,
где (ass) устанавливает связь аппликации и композиции, (dpair) – спаривания и формирования совокупности. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним характеристические равенства, которые определяют поведение операторов, задающих синтаксис и семантику языка инструкций категориальной абстрактной машины: (ass)
(x o y) z = x (y z);
(fst)
Fst [x, y] = x;
(snd)
Snd [x, y] = y;
(dpair)
<x, y> z = [x z, y z];
(ac)
ε [Λ (x) y, z] = x [y, z];
(quote)
(‘ x) y = x.
Заметим, что соотношение (ass) устанавливает связь аппликации и композиции, соотношения (fst) и (snd) – первой и второй проекций для операции образования упорядоченной пары, соотношение (dpair) – спаривания и формирования совокупности, соотношение (ac) – каррирования и апплицирования, а (quote) – цитирования. Заметим также, что данный перечень характеристических соотношений категориальной комбинаторной логики является базисным и получен с учетом устранения избыточных комбинаторов из рассматриваемой формальной системы.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Порядок трансляции в КАМ-код
1) 2) 3) 4) 5)
При трансляции в КАМ-код исходные программы подвергаются следующей последовательности преобразований: программа на функциональном языке (например, SML); ламбда-терм как формализация программы; код де Брейна (de Brujin) для ликвидации коллизий обозначений; терм ККЛ; КАМ-код (программа на языке инструкций КАМ). Затем происходит выполнение КАМ-кода с учетом среды вычислений. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Завершив этап предварительной подготовки необходимого набора соотношений, перейдем непосредственно к реализации поставленной задачи формализации процедуры трансляции функциональной программы. Схема процедуры трансляции текста программы на языке функционального программирования в результирующую последовательность инструкций категориальной абстрактной машины является многоэтапной и включает следующие стадии: 1) преобразование текста программы на языке функционального программирования в соответствующее выражение ламбда-исчисления; 2) преобразование полученного выражения ламбда-исчисления в так называемый (промежуточный) код де Брейна (de Brujin); 3) преобразование полученного кода де Брейна в терм категориальной комбинаторной логики; 4) преобразование полученного терма категориальной комбинаторной логики в последовательность инструкций категориальной абстрактной машины; 5) выполнение результирующей последовательности инструкций категориальной абстрактной машины с означиванием в среде вычислений. Подчеркнем, что собственно последовательность инструкций категориальной абстрактной машины (или, в сокращенной терминологии, КАМ-код) еще не является конечной целью нашего исследования. Итогом процедуры трансляции является выполнение результирующей последовательности инструкций категориальной абстрактной машины с означиванием в зависимости от существующей среды вычислений.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Код де Брейна
• • • •
Числом де Брейна называется глубина связывания переменной (количество ламбда-абстракций до переменной) без единицы. При трансляции в код де Брейна: числа де Брейна соответствует комбинаторам n; комбинатор S соответствует аппликации; комбинатор Λ = λx.(λz.x[y,z]) соответствует абстракции; комбинатор ‘ = K = λx.(λy.x) соответствует цитированию. Пример кодирования: λx.λy.((+x)y) → Λ(Λ(S(S(‘+1),0))). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Первый этап процедуры трансляции, а именно, преобразование текста программы на языке функционального программирования в соответствующее выражение ламбдаисчисления, был достаточно подробно рассмотрен нами ранее, в ходе изучения синтаксиса языка программирования SML в сопоставлении с синтаксисом ламбдаисчисления. Рассмотрим более подробно второй этап процедуры трансляции, который состоит в преобразовании полученного выражения ламбда-исчисления в так называемый (промежуточный) код де Брейна, названный так по имени своего создателя. Смысл перехода к коду де Брейна состоит в большей унификации записи и ликвидации коллизии обозначений переменных в ламбда-термах. Числом де Брейна называется глубина связывания переменной (которое понимается как количество ламбда-абстракций, находящихся в ламбда-терме до данной переменной) без единицы. При трансляции текста программы на языке функционального программирования в код де Брейна производятся следующие преобразования: 1) числа де Брейна, замещающие переменные ламбда-термов, заменяются на соответствующие комбинаторы n, рассмотренные в ходе предыдущей лекции; 2) операция аппликации заменяется на комбинатор S; 3) операция абстракции заменяется на комбинатор Λ = λx. (λz. x [y, z]); 4) операция цитирования (в случае наличия в ламбда-терме констант) заменяется на комбинатор цитирования ‘ = K = λx. (λy. x). Проиллюстрируем кодирование ламбда-терма по де Брейну следующим примером. Пусть требуется закодировать ламбда-терм следующего вида: λx. λy. ((+x) y). В результате получаем код де Брейна следующего вида: Λ (Λ ( S ( S (‘ +1), 0 ))).
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Среда вычислений Среда вычислений при кодировании по де Брейну понимается как конечное упорядоченное множество пар вида (<переменная>, <значение>). При трансляции ламбда-терма в код де Брейна - пару вида (<терм де Брейна>, <среда>) согласно равенствам 0![x,y] = y; (n+1)![x,y] = n! x; S[x,y]z = xz(yz); Λ (x) yz = x[y,z]; среда вырождается в пустую и обозначается как “( )”, а значения переменных явно присутствуют в коде. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В наших рассуждениях неоднократно использовалось понятие среды вычислений. Среда имеет важнейшее значение в теории и практике языков программирования, поскольку она определяет условия для выполнения той или иной программы в зависимости от характеристик компьютера, операционной системы, транслятора и другого окружения программы, в котором последняя функционирует. Из истории языков программирования естественным образом следует, что в ходе эволюции программных систем среда изменялась в сторону повышения адаптивности и универсальности. Пожалуй, апогеем развития современных вычислительных сред является исследуемая нами технологическая платформа Microsoft .NET. Формализуем понятие среды вычислений применительно к категориальной абстрактной машине. При кодировании ламбда-выражений по де Брейну среда вычислений понимается как конечное упорядоченное множество пар вида (<переменная>, <значение>). При трансляции ламбда-терма в код де Брейна, который представляет собой пару вида (<терм де Брейна>, <среда>) в соответствии с характеристическими равенствами 0! [x, y] = y; (n+1)! [x, y] = n! x; S [x, y] z = x z (y z); Λ (x) y z = x [y, z]; среда вырождается в пустую и обозначается как “( )”, а значения переменных явным образом присутствуют в результирующем коде.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Трансляция в термы ККЛ Переход от кода де Брейна к терму ККЛ выполняется на основе характеристических равенств: (ass) (x o y) z = x (y z); (fst) Fst [x, y] = x; (snd) Snd [x, y] = y; (dpair) <x, y> z = [x z, y z]; (ac) ε [Λ (x) y, z] = x [y, z]; (quote) (‘ x) y = x. При этом список «инструкций» ККЛ имеет вид: < , > Fst Snd ‘ Λ ε © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим следующий этап процедуры трансляции, который состоит в преобразовании полученного кода де Брейна в выражение категориальной комбинаторной логики. Переход от кода де Брейна к терму категориальной комбинаторной логики выполняется на основе известных характеристических равенств: (ass)
(x o y) z = x (y z);
(fst)
Fst [x, y] = x;
(snd)
Snd [x, y] = y;
(dpair)
<x, y> z = [x z, y z];
(ac)
ε [Λ (x) y, z] = x [y, z];
(quote)
(‘ x) y = x.
Таким образом, в результате данного этапа трансляции получается «программа» в форме выражения категориальной комбинаторной логики, вполне аналогичном языку программирования. При этом список «инструкций» «языка программирования» категориальной комбинаторной логики имеет следующий вид («команды» разделены пробелами и указаны без двойных кавычек): < , > Fst Snd ‘ Λ ε.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Трансляция в КАМ-код № 1. 2. 3. 4. 5. 6. 7. 8.
Переход от инструкций ККЛ к КАМ-коду выполняется согласно следующей схеме: ККЛ КАМ Пояснение Fst car Голова списка (первый элемент пары) Snd cdr Хвост списка (второй элемент пары) < push Помещение терма на вершину стека , swap Обмен значений терма и вершины стека > cons Вершина стека - в голову терма ε app Аппликация Λ cur Каррирование ‘ quote Цитирование © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим следующий этап процедуры трансляции, который состоит в преобразовании полученного выражения категориальной комбинаторной логики в «инструкции» «языка программирования» категориальной абстрактной машины. Отображение выражений категориальной комбинаторной логики в соответствующие «инструкции» категориальной абстрактной машины удобно представить в форме следующей таблицы: № п/п
Терм Инструкция ККЛ КАМ
Пояснение
1
Fst
car
Голова списка (взятие первого элемента упорядоченной пары)
2
Snd
cdr
Хвост списка (взятие второго элемента упорядоченной пары)
3
<
push
Значение терма помещается на вершину стека
4
,
swap
Значения терма и вершины стека меняются местами
5
>
cons
Вершина стека «проталкивается»
6
ε
app
Аппликация
7
Λ
cur
Каррирование
8
‘
quote
Цитирование
помещается
в
голову
терма;
стек
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Логика работы КАМ
№ 1. 2. 3.
Исходный терм языка программирования компилируется в ламбда-терм, код де Брейна, ККЛ и затем в КАМ-код. Каждая инструкция изменяет состояние КАМ, которое определяется значениями тройки {T, C, S}, где Код Обозн. Пояснение T Терм Среда вычислений (первоначально пуста) C Код «Программа» на «языке» КАМ S Стек Модель оперативной памяти компьютера Таким образом, процесс работы КАМ сводится к смене состояний вида: {T, C, S} → {T’, C’, S’}. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним, что схема процедуры трансляции текста программы на языке функционального программирования в результирующую последовательность инструкций категориальной абстрактной машины является многоэтапной и включает следующие стадии: 1) преобразование текста программы на языке функционального программирования в соответствующее выражение ламбда-исчисления; 2) преобразование полученного выражения ламбда-исчисления в код де Брейна; 3) преобразование полученного кода де Брейна в терм категориальной комбинаторной логики; 4) преобразование полученного терма категориальной комбинаторной логики в последовательность инструкций категориальной абстрактной машины; 5) выполнение результирующей последовательности инструкций категориальной абстрактной машины с означиванием в среде вычислений. При этом каждая инструкция категориальной абстрактной машины изменяет состояние КАМ, которое определяется значениями тройки {T, C, S}. Смысл состояния КАМ удобно представить в форме следующей таблицы: № п/п
Код элемента состояния КАМ
Обозначение элемента состояния КАМ
1
T
Терм
2
C
Код
3
S
Стек
Пояснение Среда вычислений (первоначально пуста) «Программа» на «языке» КАМ Модель оперативной памяти компьютера
Таким образом, процесс работы КАМ сводится к смене состояний вида: {T, C, S} → {T’, C’, S’}.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Цикл работы КАМ Циклом работы КАМ назовем множество всевозможных изменений (динамики) ее состояний (см. таблицу): T C S | T’ C’ S’ t push.C S | t C t.S t swap.C s.S | s C t.S t cons.C s.S | [s,t] C S S (cur C).C1 S | C:s C S S (quote c).C S | c C S [s,t] car.C S | s C S [s,t] cdr.C S | t C S [C:s,t] app.C1 S | [s,t] C@C1 S © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для завершения описания процедуры функционирования категориальной абстрактной машины осталось описать динамику состояний КАМ. Циклом работы КАМ назовем множество всевозможных изменений (динамики) ее состояний. Цикл работы КАМ удобно представить в форме следующей таблицы: Старое состояние КАМ Терм Код Стек t push.C S t swap.C s.S t cons.C s.S S (cur C).C1 S S (quote c).C S [s, t] car.C S [s,t] cdr.C S [C:s, t] app.C1 S
Новое состояние КАМ Терм Код Стек t C t.S s C t.S [s, t] C S C:s C S c C S s C S t C S [s, t] C@C1 S
Поскольку в данной таблице рассмотрены все возможные инструкции категориальной абстрактной машины, можно сделать вывод о том, что формализация проведена в полном объеме.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Развернутый пример вычислений на КАМ (1) Пример. Вычислить на КАМ значение суммы целых чисел 1 и 2 в каррированной форме: val curry= fn f =>fn x => fn y => f(x,y); fun sum a b = a + b; (curry sum) 1 2; Решение. 1. Результат трансляции программы в ламбда-терм: (λx. x 1 ((λx. x ) 2)) +. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем процедуру трансляции программы на языке функционального программирования в последовательность инструкций категориальной абстрактной машины с последующим вычислением результирующего значения в среде следующим показательным примером. Рассмотрим текст следующей программы на языке функционального программирования SML: val curry= fn f =>fn x => fn y => f(x,y); fun sum a b = a + b; (curry sum) 1 2; Заметим, что данная программа на языке SML реализует функцию вычисления значения суммы целых чисел 1 и 2, представленную в каррированной форме. Рассмотрим поэтапно процедуру трансляции программы на языке функционального программирования в последовательность инструкций категориальной абстрактной машины с последующим вычислением результирующего значения в среде. На первом этапе процедуры трансляции произведем преобразование текста программы на языке функционального программирования в соответствующее выражение ламбдаисчисления. В результате получим: (λx. x 1 ((λx. x ) 2)) +.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Развернутый пример вычислений на КАМ (2) 2. Результат трансляции ламбда-терма в код де Брейна: (λ.0 1 ((λ.0) 2) +. 3. Результат трансляции кода де Брейна в терм ККЛ: < Λ (< < Snd, ‘1> ε, < Λ (Snd), ‘2 > ε > ε) , ‘+> ε. 4. Результат трансляции терма ККЛ в КАМ-код: push cur (push push cdr swap quote 1 cons app swap push cur (cdr) swap quote 2 cons app cons app) swap quote + cons app 5. Создав таблицу с графами, соответствующими терму, коду и стеку КАМ, производим вычисления согласно инструкциям КАМ из п.4 до окончательного результата. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду На втором этапе процедуры трансляции произведем преобразование полученного выражения ламбда-исчисления в код де Брейна. В результате получим: (λ.0 1 ((λ.0) 2) +. На третьем этапе процедуры трансляции произведем преобразование полученного кода де Брейна в терм категориальной комбинаторной логики. В результате получим:
< Λ (< < Snd, ‘1> ε, < Λ (Snd), ‘2 > ε > ε) , ‘+> ε.
На четвертом этапе процедуры трансляции произведем преобразование полученного терма категориальной комбинаторной логики в последовательность инструкций категориальной абстрактной машины. В результате получим: push cur (push push cdr swap quote 1 cons app swap push cur (cdr) swap quote 2 cons app cons app) swap quote + cons app. На пятом этапе процедуры трансляции произведем выполнение результирующей последовательности инструкций категориальной абстрактной машины с означиванием в среде вычислений. Создав таблицу с графами, соответствующими терму, коду и стеку КАМ, производим вычисления согласно инструкциям КАМ, полученным в предыдущем пункте до окончательного результата. Последний пункт преобразований предлагается произвести самостоятельно в качестве упражнения.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Сравнение КАМ со схемой трансляции в .NET 1. 2. 3.
4. 5.
Схема трансляции в .NET содержит абстрактную машину Абстрактная машина .NET транслирует исходный текст на языке программирования в высокоуровневый ассемблер – аналог КАМ-кода Виртуальная машина .NET способна осуществлять трансляцию из широкого спектра языков программирования, в том числе, в отличие от КАМ, и для императивных языков (C++, C# и др.) Виртуальная машина .NET, как и КАМ, отличается высокой аппаратной совместимостью Виртуальная машина .NET лучше адаптирована для объектно-ориентированных языков программирования © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подводя итоги рассмотрения формальной системы категориальной комбинаторной логики и ее применения для реализации категориальной абстрактной машины на состояниях, принадлежащих пространству декартово замкнутых категорий, можно сделать следующие выводы (в сопоставлении КАМ с виртуальной машиной технологической платформы Microsoft .NET). Во-первых, как уже упоминалось ранее, схема трансляции в .NET явно содержит в своем составе абстрактную машину. Во-вторых, абстрактная машина .NET транслирует исходный текст на языке программирования в высокоуровневый ассемблер (известный под названием Microsoft Intermediate Language, или, сокращенно, MSIL), который в значительной степени является аналогичным коду категориальной абстрактной машины. В-третьих, виртуальная машина .NET способна осуществлять трансляцию из широкого спектра языков программирования, в том числе, в отличие от категориальной абстрактной машины, и для императивных языков (C++, C# и целого ряда других языков программирования). В-четвертых, виртуальная машина .NET, как и категориальная абстрактная машина, отличается высокой аппаратной совместимостью, поскольку реализует целый ряд механизмов, обеспечивающих безопасную схему вычислений. Наконец, в-пятых, отметим, что виртуальная машина .NET лучше адаптирована для объектно-ориентированных языков программирования (в том числе для языка C#, который будет рассмотрен нами во второй части курса).
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Библиография (1) 1. 2.
3. 4.
Plotkin G.D. Call-by-name, call-by-value and the λ-calculus. Theoretical computer science, 1, pp. 125-159, 1936 Cousineau G., Curien P.-L., Mauny M. The categorical abstract machine. Science of Computer Programming 8(2): 173-202, 1987 Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 Scott D.S. Domains for denotational semantics. ICALP 1982, 577-613 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать категориальную абстрактную машину и рассмотреть отдельные примеры работы ее базового варианта. Для более детального ознакомления с особенностями, достижениями и проблемами в области исследований абстрактных машин рекомендуется следующий список литературы: 1. Plotkin G.D. Call-by-name, call-by-value and the λ-calculus. Theoretical computer science, 1, pp. 125-159, 1936 2. Cousineau G., Curien P.-L., Mauny M. The categorical abstract machine. Science of Computer Programming 8(2): 173-202, 1987 3. Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 4. Scott D.S. Domains for denotational semantics. ICALP 1982, 577-613 Кратко остановимся на источниках. В работе [1] излагается взаимосвязь различных стратегий вычисления в зависимости от типа передачи параметров функции. Работа [2] содержит описание категориальной абстрактной машины. В работах [3,4] рассматриваются вопросы, связанные с теоретическим обоснованием функционирования категориальной абстрактной машины, а именно, с формальной системой комбинаторной логики и денотационной семантикой вычислений.
Современные языки программирования и .NET: I семестр Лекция 11: Категориальная абстрактная машина
Библиография (2) 5.
Hindley J.R., Seldin J.P. Introduction to combinators and λcalculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986
6.
Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение работ, посвященных исследованию категориальной абстрактной машины. Приведем окончание библиографического списка. 5. Hindley J.R., Seldin J.P. Introduction to combinators and λ-calculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986 6. Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 В работе [5] излагается взаимосвязь основополагающих формальных систем ламбдаисчисления и комбинаторной логики. В работе [6] рассматриваются вопросы, связанные с реализацией современных языков функционального программирования.
Оптимизация вычислений и расширения абстрактных машин
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к возможным направлениям и стратегиям повышения вычислительной производительности программных систем, а также моделированию этих направлений и стратегий путем внесения «конструктивных изменений» в инструкции и среду вычислений абстрактных машин.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8.
Недостатки «классической» реализации КАМвычислений Пути оптимизации КАМ-кода Расширение системы инструкций КАМ для поддержки многоместных операций и рекурсивных вычислений Стратегии вычислений. Вызов по имени и по значению Теоремы Черча-Россера о стратегиях вычислений Понятие о «ленивых» вычислениях и пути их реализации Оптимизация кода в .NET Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе лекции будут исследованы проблемы эффективности реализации языков программирования и абстрактных машин на примере категориальной абстрактной машины. Прежде всего, будут проанализированы недостатки рассмотренной в ходе предыдущих лекций базовой модификации категориальной абстрактной машины и сформулированы возможные направления оптимизации программ, представленных в терминах инструкций «классической» КАМ. В частности, будет предложено расширение системы инструкций КАМ с целью поддержки многоместных операций с параметрами функций, а также для реализации рекурсивных вычислений. Кроме того, будет представлена попытка классификации вычислительных стратегий, существующих в современных языках программирования. При этом существенное внимание будет уделено анализу вызова функций с передачей параметров по имени и по значению, а также будут рассмотрены и обсуждены формулировки теорем Черча-Россера о стратегиях вычислений. Наконец, будет изложено введение в понятийный аппарат «ленивых» (т.е. выполняемых по мере необходимости) вычислений и рассмотрены возможные пути их реализации. Формальное исследование вычислительных стратегий категориальной абстрактной машины позволит провести сравнительный анализ возможностей по оптимизации кода КАМ и виртуальной машины, применяемой в технологической платформе .NET. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Важнейшие работы по стратегиям вычислений (1) 1934 – А. Черч (Alonso Church) предложил ламбда-исчисление и исследовал порядок вычисления ламбда-термов 1936 – С. Клини (S.C. Kleene) доказал реализуемость рекурсивных вычислений средствами ламбда-исчисления 1936 – Г. Плоткин (G.D. Plotkin) исследовал вычисления с вызовом по имени и по значению на основе λ-исчисления 1950-е – Х. Карри (Haskell B. Curry) разработал комбинаторную логику как формальную систему с возможностью моделирования рекурсивных вычислений © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко остановимся на наиболее значительных (с точки зрения данного курса) этапах эволюции теории и практики реализации вычислительных стратегий в формальных теориях и языках программирования. Заметим, что рассматриваемая проблематика является основополагающей для современного computer science, и в силу этого обстоятельства значительное количество исследований, рассмотренных нами в ходе изложения курса, окажется востребованным. В 30-х г.г. А. Черч (Alonso Church) предложил исчисление ламбда-конверсий или ламбдаисчисление и применил его для исследования теории множеств. Вклад ученого был настолько фундаментальным, что теория (до сих пор называемая ламбда-исчислением и часто именуемая в литературе ламбда-исчислением Черча) является основополагающей и для рассматриваемых нами вопросов. Что касается рекурсивных вычислений, то принципиальная реализуемость рекурсии средствами математической теории была доказана С. Клини (S.C. Kleene) еще в 30-х г.г., причем фундаментом рассуждений служило ламбда-исчисление. Исследования различных стратегий передачи параметров при обращении к функциям языков программирования (в частности, вызова функций по имени и по значению) на основе ламбда-исчисления были проведены Г. Плоткиным (G.D. Plotkin). Заметим, что полученные результаты значительно позднее (уже в 70-х г.г.) были использованы для моделирования вычислений в ранних версиях языка функционального программирования ML. Несколько ранее, в 50-х г.г., Х. Карри (Haskell Curry) предложил теорию функций без переменных (иначе называемых комбинаторами), известную в настоящее время как комбинаторная логика. Эта теория представляет собой формальный язык, аналогичный языку функционального программирования и позволяющий моделировать вычисления в среде абстрактных машин, в значительной мере схожих с виртуальной машиной .NET.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Важнейшие работы по стратегиям вычислений (2) 1960-е – П. Лендин (Peter J. Landin) разработал SECDмашину – математическую формализацию для вычисления ламбда-термов 1970-е – К. Уодсворт (Christopher P. Wadsworth) предложил механизм редукции графов для моделирования «ленивых» вычислений в ламбда-исчислении 1970-е – Д. Тернер (David Turner) предложил аналогичный механизм для «ленивых» вычислений в комбинаторах
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим систематизацию наиболее значительных (с точки зрения данного курса) этапов эволюции теории и практики реализации вычислительных стратегий в формальных теориях и языках программирования. В 60-х г.г., уже в эпоху высокоуровневых языков программирования, П. Лендином (Peter J. Landin) была разработана так называемая SECD-машина, а именно, математическая формализация для реализации вычислений в терминах ламбда-выражений. Кроме того, тем же автором был создан формальный язык ISWIM (If you See What I Mean), представляющий собой вариант расширенного ламбда-исчисления и ставший впоследствии прообразом языка программирования ML, который, в свою очередь, эволюционировал в исследуемый нами язык программирования SML. Позднее, уже в 70-х г.г., К. Уодсворт (Christopher P. Wadsworth) предложил механизм редукции графов для моделирования так называемых «ленивых» (т.е. выполняемых исключительно по мере необходимости) вычислений с помощью фундаментальной формальной теории исчисления ламбда-конверсий. Несколько позже Д. Тернером (David Turner) был представлен аналогичный механизм для «ленивых» вычислений в более приближенной к практике программирования формальной системе, а именно, в терминах выражений комбинаторной логики.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Важнейшие работы по стратегиям вычислений (3) 1975 – Г.Плоткин (G.D. Plotkin) развил исследования SECDмашины и применил результаты для моделирования вычислений на языке программирования ML 1980-е – П. Кюрьен (Pierre-Louis Curien) с группой французских ученых создал КАМ как развитие SECDмашины и реализовал «ленивые» вычисления на КАМ 1980-е – Р. Хьюс (R.J.M. Hughes) предложил суперкомбинаторы как метод реализации языков программирования с оптимизацией вычислений © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Завершим систематизацию наиболее значительных (с точки зрения данного курса) этапов эволюции теории и практики реализации вычислительных стратегий в формальных теориях и языках программирования. Исследования различных стратегий передачи параметров при обращении к функциям языков программирования (в частности, вызова функций по имени и по значению) были проведены Г. Плоткиным (G.D. Plotkin) на основе развития формализации SECD-машины П. Лендина. Полученные результаты значительно позднее (уже в 70-х г.г.) легли в основу стратегии моделирования вычислений в ранних версиях языка функционального программирования ML. Затем, в 80-х г.г., группой французских ученых в составе П.-Л. Кюрьена, (Pierre-Louis Curien), Г. Кузино (Guy Cousineau), М. Мони (Michel Mauny) и ряда других исследователей удалось усовершенствовать формализацию SECD-машины П. Лендина и создать на ее основе так называемую категориальную абстрактную машину, или, сокращенно, КАМ, исследование возможностей оптимизации кода которой и будет составлять предмет нашего дальнейшего рассмотрения. Примерно в тот же период Р. Хьюсом (R.J.M. Hughes) было предложено усовершенствование комбинаторной логики и создана формальная система суперкомбинаторов (т.е. комбинаторов, на которые наложены некоторые дополнительные ограничения), которая, в частности, позволяет моделировать методы реализации языков программирования с возможностью оптимизации вычислений.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Недостатки «классической» реализации вычислений на КАМ 1. 2. 3. 4. 5.
Громоздкость вычислений Поддержка только одноместных операций Отсутствие поддержки рекурсивных вычислений Многократное вычисление повторяющихся фрагментов программы Порядок вычислений предопределен и заведомо не оптимален
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как было показано в ходе предыдущей лекции, такая формализация вычислительной машины как категориальная абстрактная машина позволяет вполне удовлетворительно реализовать модель транслятора языка функционального программирования. Кроме того, как показывает практика, именно КАМ наиболее подходит для использования в качестве виртуальной машины при реализации современных профессиональных языков функционального программирования (в частности, языка CaML), в том числе и с объектными расширениями (в частности, языка Object CaML). Тем не менее, в том базовом варианте построения категориальной абстрактной машины, который мы исследовали в ходе предыдущих лекций, существует ряд объективных недостатков, не позволяющих реализовать передовые стратегии вычислений, необходимые современным системам программирования. Перечислим наиболее существенные (с учетом целей и задач нашего курса) из этих недостатков. Прежде всего, обращает на себя внимание некоторая громоздкость вычислений, которая, хотя и объяснима отчасти низкоуровневым характером категориальной абстрактной машины, но все же неоправданно велика. Оказывается, что причиной такой ситуации является ограничение на использование категориальной абстрактной машиной только одноместных операций. Другим существенным недостатком КАМ является отсутствие поддержки рекурсивных вычислений, которое, как мы увидим впоследствии, устраняется посредством модификации среды вычислений. Наконец, очевидно, что повторяющиеся фрагменты программы требуют многократных вычислений, поскольку порядок вычислений предопределен и заведомо не оптимален.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Возможные пути оптимизации КАМ-кода 1. 2.
3. 4.
Переход к многоместным операциям Введение дополнительных функциональных инструкций для сокращения текста программ и ускорения вычислений Введение дополнительных функциональных инструкций для поддержки рекурсивных вычислений Поддержка вычислений по необходимости или «ленивых» (lazy) вычислений
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Выявив и оценив недостатки «классической» реализации категориальной абстрактной машины, наметим возможные направления оптимизации программ на языке инструкций КАМ. Прежде всего, для решения проблемы громоздкости вычислений (которая, как отмечалось, вытекает из ограниченности системы команд КАМ только одноместными инструкциями), необходимо осуществить переход к многоместным операциям, изменив синтаксис и семантику языка программирования категориальной абстрактной машины. Кроме того, в целях оптимизации кода категориальной абстрактной машины целесообразно ввести ряд дополнительных функциональных инструкций, которые обеспечивали бы ускорение вычислений при одновременном сокращении и повышении удобочитаемости текстов программ для КАМ. Затем, чтобы устранить сложности, возникающие с поддержкой категориальной абстрактной машиной рекурсивных вычислений, необходимо не только модифицировать среду, но и расширить язык программирования КАМ дополнительными функциональными инструкциями. Наконец, следует рассмотреть вопрос о реализации на основе категориальной абстрактной машины поддержки вычислений по необходимости, иначе называемых «ленивыми» (lazy).
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Переход к многоместным операциям 1. Заменим одноместные «встроенные» функции двуместными. Приведем пример записи двуместной функции сложения: + <x, y> = ε o <ε o <‘+, x >, y>. 2. C учетом характеристических равенств, получим соотношение ε o < Λ(x) o y, z > = x o , соответствующее правилу редукции в ККЛ. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Приступим к реализации усовершенствований категориальной абстрактной машины с целью оптимизации стратегии вычислений. Прежде всего, для решения проблемы громоздкости вычислений, которая обусловлена ограниченностью системы команд КАМ только одноместными инструкциями, необходимо осуществить переход к многоместным операциям. Заменим «встроенные» в систему команд категориальной абстрактной машины одноместные функции на двухместные. В частности, (в целях экономии времени, рассуждая без ограничения общности) приведем пример записи двухместной функции сложения: + <x, y> = ε o <ε o <‘+, x >, y>. C учетом характеристических равенств для категориальной абстрактной машины, выведенных в ходе предыдущих лекций, получим соотношение ε o < Λ (x) o y, z > = x o , которое находится в полном соответствии с правилами редукции, принятыми в формальной системе категориальной комбинаторной логики, на основе которой построена КАМ.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Добавление многоместных КАМ-инструкций Расширим таблицу состояний КАМ инструкциями: T C S | T’ C’ S’ true if a b c sm | S ac m false if a b c sm | S bc m (a, b) add c S | {a+b} C S (a, b) eq c S | true/false C S Введены операции сравнения if, проверки условия eq и сложения add. Пример. КАМ-код для сложения чисел 2 и 3 сократится: push quote 2 swap quote 3 cons add. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение осуществления перехода к многоместным операциям в языке программирования категориальной абстрактной машины. Пересмотрим цикл работы (схему смены состояний) категориальной абстрактной машины, расширив пространство состояний КАМ дополнительными инструкциями, которые, по аналогии с основными командами КАМ, представим в форме следующей таблицы: Старое состояние КАМ Терм Код Стек true if a b c sm false if a b c sm (a, b) add c S (a, b) eq c S
Новое состояние КАМ Терм Код Стек S ac m S bc m {a + b} C S true / false C S
Как видно из приведенной таблицы, пространство состояний категориальной абстрактной машины расширено посредством введения операций сравнения if, проверки условия eq, а также сложения add. Проиллюстрируем практическую эффективность программного кода усовершенствованной категориальной абстрактной машины следующим примером. Рассмотрим программу категориальной абстрактной машины, вычисляющую сумму целых чисел 2 и 3 в «классической» версии «языка программирования» КАМ: push cur (push push cdr swap quote 1 cons app swap push cur (cdr) swap quote 2 cons app cons app) swap quote + cons app. Запрограммируем ту же задачу в усовершенствованной версии КАМ: push quote 2 swap quote 3 cons add. Как видно, объем программы сократился более чем втрое.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Поддержка рекурсии Расширим таблицу состояний КАМ еще двумя дополнительными инструкциями: T t [a:b]
C dum c wind c
S | S | (t$Y)S |
T’ C’ $Y C (t.[a:b]) C
S’ S S
Введены операции аппликации wind и dum для обработки рекурсивных объектов. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим, каким образом можно решить проблему с рекурсивными вычислениями в категориальной абстрактной машине, которая сводится к принципиальной цикличности и потенциальной бесконечности обрабатываемых инструкций. Чтобы устранить сложности, возникающие с поддержкой категориальной абстрактной машиной рекурсивных вычислений, необходимо расширить язык программирования КАМ дополнительными функциональными инструкциями. Пересмотрим цикл работы (схему смены состояний) категориальной абстрактной машины, расширив пространство состояний КАМ дополнительными инструкциями, которые, по аналогии с основными командами абстрактной машины, представим в форме следующей таблицы: Старое состояние КАМ Терм Код Стек T dum c S [a : b] wind c (t $Y) S
Новое состояние КАМ Терм Код Стек $Y C S (t. [a : b]) C S
Как видно из приведенной таблицы, пространство состояний категориальной абстрактной машины расширено посредством введения операций wind и dum для обработки рекурсивных объектов.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Стратегии вычислений При вычислении с вызовом по значению (call-by-value) все выражения должны быть означены до аппликации. При вычислении с вызовом по имени (call-by-name) до аппликации необходима подстановка термов вместо всех вхождений формальных параметров до означивания. При вычислении с вызовом по необходимости (call-byneed) ранее вычисленные значения аргументов хранятся, если необходимо их повторное использование. Замечание. Возможность ленивых вычислений в языках функционального программирования обусловлена теоремой ЧерчаРоссера. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду До сих пор рассматривались варианты абстрактных машин, реализующих механизм означивания переменных, известный под названием вызова по значению. Однако существуют и другие стратегии вычислений. Рассмотрим более подробно возможные подходы к означиванию переменных. При вычислении с вызовом по значению (call-by-value) все выражения должны быть означены до вычисления операции аппликации. При вычислении с вызовом по имени (call-by-name) до вычисления операции аппликации необходима подстановка термов вместо всех вхождений формальных параметров до означивания. Именно эта стратегия лежит в основе «ленивых» (lazy), «отложенных» (delayed) или «замороженных» (frozen) вычислений, которые принципиально необходимы для обработки потенциально бесконечных структур данных. Наконец, при вычислении с вызовом по необходимости (call-by-need) ранее вычисленные значения аргументов сохраняются в памяти компьютера только в том случае, если необходимо их повторное использование. Чтобы устранить сложности с поддержкой категориальной абстрактной машиной «ленивых» вычислений, пересмотрим цикл работы КАМ, расширив пространство состояний дополнительными инструкциями для «замораживания» (freeze) и «размораживания» (unfreeze), которые представим в форме следующей таблицы: Старое состояние КАМ Терм Код Стек s (freeze C).C1 S C.s unfreeze.C S s unfreeze.C S
Новое состояние КАМ Терм Код Стек С.s C1 S s C S s C S
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Теоремы Черча-Россера Теорема Черча-Россера. Пусть E1 = E2 ламбда-термы. Тогда существует ламбда-терм E такой, что E1=E и E2=E. (“=“ понимается в смысле отношения конвертируемости). Теорема Черча-Россера (1). Если в языке вызовы по имени и по значению приводят к определенному результату, то это один и тот же результат. Теорема Черча-Россера (2). Если вычисление значения выражения приводит к определенному результату, то к нему всегда приводит вызов по имени и не всегда – по значению. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Сформулируем ряд теорем, известных по именам их авторов как теоремы Черча-Россера и позволяющих установить особенности различных вычислительных стратегий, а также взаимосвязей между ними. Заметим, что возможность «ленивого» связывания переменных с их значениями в языках функционального программирования вытекает из формулировки теорем Черча-Россера. Поскольку доказательство теорем Черча-Россера выходит за рамки настоящего курса, ограничимся приведением формулировок теорем как таковых. Теорема Черча-Россера. Пусть E1 и E2 суть ламбда-выражения, причем справедливо соотношение: E1 = E2. Тогда существует ламбда-выражение E такое, что выполнены следующие условия: вопервых, E1 = E, и, во-вторых, E2 = E. Заметим, что символ “=“ в формулировке теоремы понимается в смысле отношения конвертируемости. Теорема Черча-Россера (1). Если в языке вызовы по имени и по значению приводят к определенному результату, то это один и тот же результат. Теорема Черча-Россера (2). Если вычисление значения выражения приводит к определенному результату, то к нему всегда приводит вызов по имени и не всегда – по значению.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Возможные способы реализации стратегии «ленивых» вычислений 1) расширения абстрактных машин («чистые» SECD и КАМ реализуют стратегию вызова по значению; необходима модификация среды вычислений); 2) редукция графов как механизм преобразования ламбда-термов для обеспечения единственности означивания каждого аргумента; 3) исследование комбинаторов специального вида (суперкомбинаторов) и разработка алгоритмов оптимизации кода. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду После выяснения особенностей различных вычислительных стратегий, а также взаимосвязей между ними, наметим возможные направления реализации стратегии «ленивых» вычислений. Наиболее очевидным, исходя из специфики курса, представляется подход, при котором пересматривается цикл работы категориальной абстрактной машины, причем пространство состояний расширяется дополнительными инструкциями для «замораживания» (freeze) и «размораживания» (unfreeze), ранее (в ходе данной лекции) представленными нами в виде таблицы. Напомним, что ни SECD-машина П. Лендина, ни категориальная абстрактная машина в «чистом», «классическом» представлении не обладают способностью поддержки реализации механизма отложенного означивания переменных. Другим возможным подходом к реализации «ленивой» стратегии вычислений может служить использование механизма редукции графов для преобразования ламбдавыражений, который обеспечивает единственность означивания для каждого аргумента. Наконец, еще одним теоретически интересным и практически важным подходом к реализации стратегии отложенных вычислений является предложеное Р. Флойдом усовершенствование комбинаторной логики в виде формальной системы суперкомбинаторов. Заметим, что последнее направление является весьма важным еще и в силу того обстоятельства, что оно позволяет моделировать методы реализации языков программирования с возможностью алгоритмизированной оптимизации программного кода.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Преимущества использования платформы .NET для оптимизации кода 1) использование виртуальной машины с универсальным высокоуровневым ассемблером MSIL; 2) централизованная «сборка мусора», обработка ошибок и исключительных ситуаций; 3) языковая интероперабельность (разработка компонент проекта на наиболее целесообразных языках программирования); 4) широкий спектр унифицированных предопределенных типов и структур данных. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подводя итоги сравнительного анализа стратегий вычисления и направлений их оптимизированной реализации на основе категориальной абстрактной машины, можно сделать следующие выводы (в сопоставлении КАМ с виртуальной машиной технологической платформы Microsoft .NET). Во-первых, необходимо отметить, что в рамках рассматриваемой инструментальнотехнологической платформы Microsoft .NET используется виртуальная машина с универсальным высокоуровневым ассемблером (известным под названием Microsoft Intermediate Language, или, сокращенно, MSIL) принципиально подобная КАМ. Абстрактная машина .NET транслирует исходный текст на языке программирования в код MSIL, который в значительной степени является аналогичным КАМ-коду. Во-вторых, виртуальная машина инструментально-технологической платформы Microsoft .NET является достаточно универсальным решением и предусматривает такие важнейшие механизмы поддержки проектирования и реализации языков программирования, как централизованная «сборка мусора», обработка ошибок и исключительных ситуаций. Кроме того, виртуальная машина .NET, как и категориальная абстрактная машина, отличается высокой аппаратной совместимостью, поскольку реализует целый ряд механизмов, обеспечивающих безопасную схему вычислений. В-третьих, виртуальная машина .NET, в отличие от категориальной абстрактной машины, поддерживает широкую языковую интероперабельность, то есть возможность одновременной разработки программных проектов на различных языках программирования в условиях одной и той же универсальной среды вычислений. Таким образом, представляется принципиально возможной и практически реализуемой разработка компонент проекта на наиболее целесообразных языках программирования. В-четвертых, виртуальная машина .NET обеспечивает поддержку универсальной среды вычислений с широким спектром унифицированных предопределенных типов и структур данных.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Вопросы, рассмотренные в рамках курса 1) классификация подходов к программированию; 2) математическое обоснование функционального программирования (ламбда-исчисление, комбинаторная логика, теория категорий); 3) синтаксис и семантика языков программирования; 4) теория типов и типизация; 5) рекурсивные вычисления; 6) реализация языков программирования (SECD, КАМ); 7) стратегии вычислений и оптимизация кода. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Завершая первую часть учебного курса, посвященного исследованию современных языков программирования (на примере языка программирования SML) и поддерживающих их сред вычислений (на примере инструментально-технологической платформы .NET), кратко резюмируем содержание рассмотренных вопросов и проблем. Прежде всего, нами была рассмотрена история развития языков программирования, а также построен вариант классификации современных подходов к программированию. Затем было дано представление важнейших математических формальных систем, которые составляют теоретическое основание современных подходов к программированию и, прежде всего, функционального подхода. В частности, были рассмотрены исчисление ламбда-конверсий, комбинаторная логика, а также теория категорий и теория вычислений Д. Скотта. Далее, посредством перечисленных теорий были формализованы такие важнейшие аспекты языков программирования, как синтаксис и семантика. Кроме того, было исследовано интуитивно ясное понятие типа, изучены основы теории типов и типизации в языках программирования. После этого, мы перешли к рассмотрению вопросов, связанных с представлением рекурсивных функций и множеств, а также к формализации рекурсивных вычислений. Еще одним пунктом исследований стали важнейшие аспекты реализации языков программирования, включая схему трансляции в промежуточнные коды виртуальных машин SECD и КАМ. Наконец, были исследованы в сравнении различные стратегии вычислений и оптимизации кода.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Вопросы, планируемые к дальнейшему рассмотрению в рамках курса 1) математическое обоснование объектного подхода к программированию (на примере языка C#); 2) компонентное проектирование интегрированных гетерогенных программных систем (на примере языков SML и C#); 3) теория и практика разработки событийно управляемых приложений; 4) сравнительное исследование функционального и объектно-ориентированного подходов к программированию. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Вполне естественно, что, исходя из обширного спектра и существенной глубины рассматриваемой проблематики, ряд важнейших аспектов реализации современных языков программирования (в рамках первой части курса) был лишь обозначен или изложен весьма конспективно. В связи с этим, в ходе дальнейшего исследования планируется систематическое изучение следующих вопросов: 1) математическое обоснование объектного подхода к программированию (на примере языка программирования C#); 2) компонентное проектирование интегрированных гетерогенных программных систем (на примере языков функционального программирования SML и объектноориентированного программирования C#); 3) теория и практика разработки событийно управляемых приложений; 4) сравнительное исследование функционального и объектно-ориентированного подходов к программированию. Дальнейшие исследования, согласно практике, сложившейся на протяжении первой части курса, будут проводиться синтетически по направлениям теоретического обоснования программирования на основе современных формальных систем computer science и современной практики проектирования и реализации программного обеспечения на основе универсальной и прогрессивной программно-инструментальной платформы Microsoft .NET.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Библиография (1) 1. 2. 3. 4.
5.
Barendregt H.P. The lambda calculus (revised edition), Studies in Logic, 103, North Holland, Amsterdam, 1984 Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 Kleene S.C. λ-definability and recursiveness. Duke Math. J., pp. 340-353, 1936 Hughes R.J.M. Super combinators: a new implementation method for applicative languages. Proc. of the 1982 ACM Symposium on LISP and Functional Programming, Pittsburgh, 1982 Landin P.J. The next 700 programming languages. CACM, 9, pp. 157-164, 1966 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать основные направления теории представления вычислительных стратегий и рассмотреть отдельные примеры, связанные с практикой их реализации. Для более детального ознакомления с особенностями, достижениями и проблемами в области исследований вычислительных стратегий рекомендуется следующий список литературы: 1. Barendregt H.P. The lambda calculus (revised edition), Studies in Logic, 103, North Holland, Amsterdam, 1984 2. Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 3. Kleene S.C. λ-definability and recursiveness. Duke Math. J., pp. 340-353, 1936 4. Hughes R.J.M. Super combinators: a new implementation method for applicative languages. Proc. of the 1982 ACM Symposium on LISP and Functional Programming, Pittsburgh, 1982 5. Landin P.J. The next 700 programming languages. CACM, 9, pp. 157-164, 1966 Кратко остановимся на источниках. Работа [1] является энциклопедией ламбдаисчисления – фундаментальной формальной теории для данного курса. Работа [2] содержит описание формальной системы комбинаторной логики. В работе [3] исследуются модели рекурсивных вычислений. В работах [4,5] обсуждаются вопросы практической реализации языков программирования, в том числе на основе суперкомбинаторов.
Современные языки программирования и .NET: I семестр Лекция 12: Оптимизация вычислений и расширения абстрактных машин
Библиография (2) 6. 7. 8.
9.
Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 Plotkin G.D. Call-by-name, call-by-value and the λ-calculus. Theoretical computer science, 1, pp. 125-159, 1936 Cousineau G., Curien P.-L., Mauny M. The categorical abstract machine. Science of Computer Programming 8(2): 173-202, 1987 Wadsworth C.P. Semantics and pragmatics of the λ-calculus. PhD Thesis, University of Oxford, 1981 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение работ, посвященных исследованию важнейших вычислительных стратегий. Приведем окончание библиографического списка. 6. Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 7. Plotkin G.D. Call-by-name, call-by-value and the λ-calculus. Theoretical computer science, 1, pp. 125-159, 1936 8. Cousineau G., Curien P.-L., Mauny M. The categorical abstract machine. Science of Computer Programming 8(2): 173-202, 1987. 9. Wadsworth C.P. Semantics and pragmatics of the λ-calculus. PhD Thesis, University of Oxford, 1981. В работе [6] излагаются вопросы практической реализации языков функционального программирования. В работе [7] представлен сравнительный анализ вычислительных стратегий. Работа [8] содержит описание категориальной абстрактной машины. Работа [9] посвящена исследованию семантического и прагматического аспектов исчисления ламбда-конверсий.