Баева Н.В., Большакова Е.И., Груздева Н.В. Программные средства поддержки практикума

advertisement
Баева Н.В., Большакова Е.И., Груздева Н.В.
Программные средства поддержки практикума
по функциональному программированию
Введение
Функциональное программирование развивается с 60-х годов
прошлого века, и за прошедшее время возникло несколько десятков
функциональных языков, включая наиболее старый и известный
Лисп [13] и менее распространенные языки ML, Miranda, Hope и
др. [12], используемые преимущественно в академической среде. В
рамках различных функциональных языков были исследованы
ключевые концепции функциональной парадигмы программирования
(использованные затем, в частности, в технологии MapReduce), а также
были выработаны языковые средства, постепенно интегрируемые в
последние годы в различные императивные и объектные языки
программирования. Для последних десятилетий характерно также
появление таких функциональных языков как Haskell, Closure, Erlang,
F#, которые учитывают технологические аспекты современного
программирования, разработаны для разных платформ и все чаще
применяются в промышленном программировании.
Повышение роли функциональных языков в современной ITиндустрии требует соответствующей модернизации университетских
программ обучения по информатике и программированию. На кафедре
алгоритмических языков (АЯ) факультета ВМК МГУ обучение
функциональному программированию велось уже с середины 90-х гг. –
в рамках кафедрального практикума на базе языков Рефал [7, 10] и
Лисп [4, 13], к которым в 2011 г. добавился также современный язык
Хаскель [5, 6, 17]. В 2013 г. в рамках новой бакалаврской программы
был дополнительно введен кафедральный курс лекций по
функциональному программированию, и соответственно был обновлен
практикум, включающий несколько практических заданий по этим
функциональным языкам.
Практическое изучение функциональных языков требует
подходящих программных средств (в том числе интерпретаторов и
компиляторов функциональных языков). Для проведения практикума на
Лиспе не возникало проблем, поскольку в открытом доступе есть
несколько интерпретаторов этого языка, поддерживающих его
фактический стандарт – Common Lisр [16]. Для языка Хаскель также
существует несколько доступных интерпретаторов и компиляторов.
Однако по сравнению с Лиспом язык Хаскель содержит гораздо более
сложные по семантике вычислений конструкции, для освоения которых
крайне полезны специальные средства поддержки практикума, в первую
очередь – средства визуализации пошагового вычислений хаскельвыражений.
Что касается языка Рефал, точнее, его диалекта Рефал-2,
используемого в кафедральном практикуме по функциональному
программированию [3], то с подходящим программным обеспечением
были проблемы. Язык программирования Рефал – отечественная
разработка, и с начала 90-х гг. исследовательскими группами развивался
в основном диалект Рефал-5 [11]. Реализованный же еще в 80-х годах (и
достаточно эффективно) интерпретатор для языка Рефал-2 [7, 8] был
создан для 16-битной ОС MS-DOS и технологически устарел. Поэтому
одной из задач поддержки практикума на языке Рефал была разработка
нового, современного рефал-интерпретатора, подходящего для учебных
целей, а также создание соответствующей интегрированной среды
разработки рефал-программ.
В данной работе характеризуются программные средства,
разработанные на кафедре АЯ факультета ВМК МГУ в поддержку
практикума по функциональному программированию: интерпретатор
для языка Рефал (названный Рефал-2У) и среда разработки рефалпрограмм, а также средство пошаговой интерпретации и визуализации
выражений языка Хаскель. Программная реализация этих средств
выполнена студентами кафедры Д. Кулаковым, А.Тодуа, О. Баевым в
рамках их выпускных работ. Реализованные средства предназначены в
первую очередь для использования начинающими программистами –
студентами 3 курса, изучающими языки Рефал-2 и Хаскель.
Перед собственно описанием разработанных программных
средств в данной работе кратко обосновывается выбор языков для целей
обучения функциональному программированию.
Языки для обучения
функциональному программированию
Изучение студентами основополагающих концепций и техники
функционального программирования ведется в рамках лекционного
курса и практикума кафедры АЯ на базе трех языков: Лиспа, Рефала и
Хаскеля. Выбор указанных языков был обусловлен рядом
обстоятельств.
Главная цель лекционного курса и практикума – охватить
ключевые механизмы и языковые средства известных функциональных
языков и по возможности показать их существенные различия и
особенности. С этой точки зрения выбор Лиспа и Хаскеля как основных
языков лекционного курса вполне закономерен, поскольку они имеют
ряд принципиальных различий, но в совокупности демонстрируют
основные возможности функционального программирования.
Лисп – исторически первый функциональный язык, оказавший
мощное влияние на развитие всей функциональной парадигмы
программирования. Он имеет очень простой синтаксис (и это явное
достоинство при его изучении), а его функциональное ядро [15]
включает лишь одну структуру данных – список, и всего 8 базовых
встроенных
функций
над
списками,
которые
позволяют
запрограммировать любой алгоритм символьной обработки. Принятая в
Лиспе динамическая типизация (по сути ее отсутствие) также облегчает
его изучение. В тоже время гибкая структура лисповского списка
позволяет изучить разные виды рекурсии, включая рекурсию высшего
порядка. В лисп-программах применяются анонимные функции и
функционалы (функции высших порядков), хотя их использование не
всегда столь органично, как в более современных языках.
Хаскель – один из самых мощных по средствам и поэтому
непростых современных функциональных языков, с более высоким
порогом вхождения, чем Лисп. Функция в Хаскеле уже вполне объект
первого класса [12]. Кроме списков в Хаскеле используются другие
структуры данных и есть возможность конструирования новых
структур. Семантика вычислений существенно отличается от
лисповской: встроенное каррирование функций, "ленивое" вычисление,
статическая типизация выражений и статический (лексический) способ
связывания. Отличен от лисповского и синтаксис хасель-программ (он
восходит к функциональному языку ML).
В то же время Хаскель развивает рекурсивную технику Лиспа в
отношении функционалов. Тем самым последовательное изучение
основных средств Лиспа, а затем Хаскеля существенно упрощает
вхождение в последний. Вхождение в этот язык облегчается также за
счет предварительного изучения языка Рефал (оно ведется в рамках
кафедрального практикума , но не входит в лекционный курс).
Рефал – один из первых языков программирования, где была
предложена концепция образца выражения и сопоставления с
образцом. Эта возможность отсутствует в Лиспе, но имеется в
несколько упрощенном виде в Хаскеле. Кроме того, общая структура
описания рефал-функций как последовательности предложений,
удовлетворяющих определенным образцам, сходна со структурой
описания хаскель-функций. Среди существующих диалектов Рефала для
изучения в рамках практикума был выбран Рефал-2, поскольку именно
в нем представлены наиболее мощные и гибкие средства сопоставления
с образцом, в том числе спецификаторы.
Заметим, что в рамках лекционного курса по функциональному
программированию из-за ограниченности времени изучаются лишь
основы языка Хаскель, без выполнения практических задач. Обучение
этому языку продолжается в рамках последующего практикума,
включающего практические задания.
Интерпретатор языка Рефал-2У
Достаточно долгое время в рамках практикума по
функциональному программированию применялся интерпретатор языка
Рефал-2, разработанный в конце 80-х гг. еще для ОС MS-DOS [8].
Скомпилированный тогда исполняемый модуль в настоящее время
вполне работоспособен, но его запуск возможен только при
использовании эмулятора ОС DOS (DOSBox), т.е. создает
дополнительные
технические
сложности.
Попытки
сборки
интерпретатора по сохранившемуся исходному коду на языке
программирования С не увенчались успехом, т.к. исходный код требует
существенной переработки. Кроме того, поддерживаемый старым
рефал-интерпретатором диалект языка сохраняет особенности,
связанные с записью программы на перфокартах. В связи с этим
возникла задача разработки для учебного процесса нового,
современного рефал-интерпретатора, которая была успешно решена [9].
Разработанный в виде консольного приложения интерпретатор и
поддерживаемый им язык получили название Рефал-2У.
В ходе разработки и реализации нового интерпретатора были
проанализированы основные программные решения, принятые в старой
реализации, в первую очередь язык сборки [8], используемый для
внутреннего представления и эффективной интерпретации рефалфункций. Часть программных решений была применена в новом
интерпретаторе, но с определенными модификациями (двусвязный
список для представления рефал-выражений, модифицированная
система команд языка сборки рефал-программ). Вместе с этим в
реализации Рефал-2У были предложены новые программные решения, в
частности, представление спецификаторов языка Рефал виде множеств,
что позволяет более эффективно осуществлять проверку соответствия
выражения спецификатору.
Важным при разработке интерпретатора было максимально
сохранить языковую совместимость с существующим диалектом языка
Рефал-2, отказавшись лишь от языковых средств, совсем не
используемых в студенческих программах по практикуму (к таким
средствам относятся, в частности, динамические ящики Рефала). Из
сколь-нибудь существенных нарушений языковой совместимости было
введенное требование описания именованого спецификатора до его
первого использования (поскольку это легко выполнимо при
программмировании).
Реализация интерпретатора Рефал-2У проведена на языке С++,
в итоге получен кроссплатформенный интерпретатор, который был
протестирован на рефал-программах студенческого практикума, под
управлением современных ОС, включая Ubuntu 13.04, Windows 8.1, Mac
OS Yosemite.
Интегрированная среда разработки рефал-программ
Под
интегрированной
средой
разработки
(Integrated
Development Environment – IDE) понимают обычно единую
программную систему, поддерживающую все этапы разработки
программы, начиная с написания исходного кода вплоть до ее
компиляции и отладки. Поскольку существующие IDE (как
коммерческие, так и открытые) не поддерживают работу с
функциональным языком Рефал, для этого языка была разработана
подобная интегрированная среда, причем с учетом специфики языка
Рефал. Среда предназначена в первую очередь для студентов,
изучающих этот язык и пишущих свои первые рефал-программы.
По результатам анализа функциональных возможностей
известных интегрированных сред разработки для различных языков
программирования были определены те средства, которые существенно
облегчают процесс создания рефал-программ. Эти средства
охватывают:
 функции работы с текстами программ, включая автодополнение
при вводе, проверку парности скобок рефал-выражений,
составление списка определенных пользователем рефал-функций;
 средства запуска и отладки рефал-программ, позволяющие
выполнять синтаксическую проверку корректности рефалвыражений
за
счет
вызова
интегрированного
рефалинтерпретатора;
 интегрированная справочная система по возможностям языка
Рефал-2У.
Особым требованием к создаваемой среде являлось требование
портативности, простоты установки и использования.
Указанные выше средства были воплощены в интегрированной
среде разработки рефал-программ, реализованной на платформе .NET
Framework, и включающей в себя:
 редактор текстов программ, основой для которого служит
библиотека AvalonEdit [14];
 интерпретатор для языка Рефал-2;
 справочную систему в формате CHM (Microsoft Compiled HTML
Help), достаточную для изучения языка.
Редактор текстов программ, входящий в разработанную среду,
предоставляет следующие возможности:
 Стандартные функции работы с текстом:
o создание, сохранение и открытие файлов для
редактирования;
o копирование, вставка и поиск фрагментов текста.
 Типичные функции интегрированных сред:
o нумерация строк программы и подсветка синтаксиса;
o функция автодополнения при вводе имен функций;
o сокрытие и отображение фрагментов кода.
Для реализации подсветки синтаксиса используется XMLдокумент, содержащий в себе набор правил, основанный на регулярных
выражениях. Приведем пример такого правила, применяемого для
выделения цветом ключевых слов языка:
<!-- Ключевые слова -->
<Keywords foreground="#0000FF">
<Word>start</Word>
<Word>extrn</Word>
<Word>entry</Word>
<Word>end</Word>
<Word>empty</Word>
</Keywords>
В ходе работы пользователя в среде формируется список
определенных им рефал-функций, который используется для
реализации автодополнения текста при его вводе, а также для
отображения списка функций в области быстрой навигации по тексту
(отдельная область основного окна среды). Щелкнув мышью на имя
функции в списке, можно сразу попасть в строку рефал-програмы, в
которой начинается определение функции.
Для удобства работы с текстом программы в редакторе есть
возможность сокрытия фрагментов кода, а именно тех его частей, в
которых находятся строки, определяющие функцию. При этом полный
текст определения функции скрывается, остается лишь одна строка,
щелчок мышью по которой дает возможность увидеть текст функции
целиком. Таким образом, можно, не меняя текст программы, сделать его
более компактным и обозримым.
Интегрированная среда позволяет запустить на вычисление
текущий редактируемый код рефал-программы. Если загрузка
программы в интерпретатор проходит успешно, то результаты ее
вычисления показываются в окне вызванного интерпретатора. В случае
выявления ошибок программа не вычисляется, а в области быстрой
навигации появляется список обнаруженных ошибок. При щелчке
мышью
на
конкретную
ошибку
происходит
переход
в
соответствующую строку кода рефал-программы.
Основное окно пользовательского интерфейса среды
разработки представлено на Рис. 1. Основная часть окна предназначена
для редактирования программы, а справа расположена область быстрой
навигации. В этой области можно видеть два блока: блок со списком
выявленных в программе ошибок и блок, содержащий в себе список
определенных пользователем функций. При желании область быстрой
навигации можно скрыть.
Рис 1. Окно интегрированной среды разработки рефал-программ
Включенный в интегрированную среду справочник по языку
Рефал-2 был создан с помощью программы Doc-To-Chm [18], исходя из
текста учебного пособия [3], который был переформатирован особым
образом для приведения к формату, пригодному для конвертации в
CHM-формат. Полученный в результате файл-справка был включен в
состав среды. Особенность формата созданного справочника позволяет
отчуждать его от системы и использовать автономно или же включать
его в состав других программных продуктов.
Средство пошаговой интерпретации и визуализации
выражений языка Хаскель
Поскольку шаги вычисления даже в случае не очень сложных
выражений языка Хаскель далеко не всегда очевидны, разработанное
программное средство предоставляет пользователю удобный интерфейс
для ввода хаскель-выражения и просмотра результатов его пошаговой
интерпретации.
В состав программного средства входят следующие модули:
 компилятор языка Хаскель;
 свободно распространяемая библиотека simple-reflect [1] пошаговой
интерпретации простых выражений языка Хаскель;
 дополнительно разработанная на Хаскеле библиотека ap-reflect [2]
пошаговой интерпретации хаскель-выражений, содержащих
аппликативные функторы;
 центральный
модуль,
осуществляющий
подключение
перечисленных выше модулей для вычисления хаскель-выражений
и реализующий взаимодействие с пользователем.
Библиотека simple-reflect позволяет получить результаты
пошагового вычисления выражений, содержащих различные функции и
функционалы языка Хаскель, однако она не поддерживает вычисление
выражений с частично применёнными функциями и, как следствие,
выражений с аппликативными функторами. Однако демонстрация
процесса вычисления таких выражений не менее полезна – именно для
этого на Хаскеле была разработана библиотека ap-reflect, совместимая с
библиотекой simple-reflect.
Особенностью применения двух данных библиотек является
специальное синтаксическое оформление исходного интерпретируемого
хаскель-выражения, которое необходимо для его корректной пошаговой
интерпретации. Например, для вывода результатов пошагового
вычисления выражения foldr(+)0 [1,2,3] необходимо оформить
его как mapM_ print . reduction $ foldr (+) 0 [1,2,3]
а выражение
(+)<$> Just 5 <*> Just 7
записать как
mapM_ print . reduction $(.+) -$- Just 5 -*- Just 7
Добавленные в начало этих выражений функции (а именно:
mapM_ print . reduction) обеспечивают формирование и вывод
строк – промежуточных результатов вычисления выражения, стоящего
после знака $. Дополнительно во втором выражении некоторые
стандартные операции Хаскеля заменены на их аналоги, определённые
в библиотеке ap-reflect, что необходимо для получения результатов
промежуточных вычислений.
Центральный модуль разработанного средства пошаговой
интерпретации и визуализации реализован на языке С# с
использованием технологии WРF (Windows Presentation Foundation).
Поддерживаемый модулем интерфейс освобождает пользователя от
необходимости специального синтаксического оформления хаскельвыражений для их пошаговой интерпретации.
Укажем основные этапы обработки входного выражения:
1. Синтаксический анализ хаскель-выражения, выполняемый по мере
его ввода. Различные конструкции выражения выделяются разными
цветами, что позволяет пользователю быстрее заметить
допущенные им опечатки и ошибки.
2. Преобразование введённого выражения к синтаксическому виду,
требуемому библиотеками simple-reflect и ap-reflect. Для
преобразования используются шаблоны замены одних операций на
другие (например, <$> заменяется на -$-) , а также вставки в
начало
выражения
вызовов
дополнительных
функций
(mapM_ print . reduction $).
3. Компиляция файла с преобразованным выражением и файлов
библиотек, запуск полученного исполняемого файла, считывание
результата его вычисления (т.е. записи пошаговой интерпретации).
Вывод полученного результата в окно пользовательского
интерфейса в виде последовательности строк-шагов вычисления, с
подсветкой разными цветами различных конструкций языка
Хаскель. В случае ввода пользователем (на этапе 1) выражения,
содержащего синтаксические или семантические ошибки, в окно
интерфейса будет выведено диагностическое сообщение,
полученное при попытке вычислить данное выражение (на этапе 3).
Окно пользовательского интерфейса – см. Рис. 2, включает два
рабочих поля: для ввода хаскель-выражения и вывода результата его
пошаговой интерпретации (в последнее выводятся также сообщения об
ошибка). Две кнопки (одинарная и двойная стрелка) служат
соответственно для вывода в окно результата очередного шага
вычислений или сразу всех шагов.
4.
Рис. 2. Пользовательский интерфейс средства
пошаговой интерпретации и визуализации хаскель-выражений
Заключение
В работе охарактеризованы функциональные возможности и
особенности реализации программных средств, разработанных в
поддержку практикума по функциональному программированию:
интерпретатор языка Рефал-2У, среда разработки рефал-программ,
средство пошаговой интерпретации и визуализации выражений языка
Хаскель. Главное их назначение – создание условий для более
эффективного и комфортного практического изучения этих языков
студентами. Ясно, что возможности этих средств могут быть
расширены, в частности, планируется включить в интерпретатор
Рефал-2У дополнительные средства отладки рефал-программ.
Литература
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
Библиотека simple-reflect [Электронный ресурс]. – Электрон. дан. –
URL: http://hackage.haskell.org/package/simple-reflect
(дата обращения: 21.02.2015).
Библиотека ap-reflect [Электронный ресурс]. – Электрон. дан. –
URL: http://hackage.haskell.org/package/ap-reflect-0.2
(дата обращения: 28.03.2015).
Большакова Е.И., Груздева Н.В. Основы программирования на
языке Рефал: Учебное пособие. – М.: МАКС Пресс, 2009. – 92 с.
Большакова Е.И., Груздева Н.В. Основы программирования на
языке Лисп: Учебное пособие. – М.: МАКС Пресс, 2010. – 112 с.
Душкин Р.В. Функциональное программирование на языке Haskell –
М.: ДМК Пресс, 2006. – 608 с.
Миран Липовача Изучай Haskell во имя добра! /Пер. с англ. – М.:
ДМК Пресс, 2012. – 490 с.
Романенко С.А. Метаалгоритмический язык Рефал и тенденции его
развития // Искусственный интеллект, Кн. 3. Программные и
аппаратные средства: Справочник / под ред.Захарова В.Н.,
Хорошевского В.Ф. – М: Радио и связь, 1990, стр. 47–55.
Романенко С.А. Реализация Рефала-2. М: ИПМ АН СССР, препринт
№ 71, 1987.
Тодуа А.Р. Разработка интерпретатора языка Рефал // Сборник
тезисов лучших дипломных работ 2015 года. – М.: МАКС Пресс,
2015, с. 98-100.
Турчин В.Ф. Алгоритмический язык рекурсивных функций
(РЕФАЛ). М: ИПМ АН СССР, Препринт № 4, 1968.
Турчин В.Ф. РЕФАЛ-5. Руководство по программированию и
справочник. http://www.refal.net/rf5_frm.htm
Филд А., Харрисон П. Функциональное программирование: Пер. с
англ. – М.: Мир, 1993.
Хювёнен Э., Сеппянен Й. Мир Лиспа. Том 1. Введение в язык Лисп
и функциональное программирование: Пер. с англ. – М: Мир, 1990.
AvalonEdit [Электронный ресурс]. – Электрон. дан. –
URL: http://avalonedit.net/ (дата обращения: 19.10.2015)
McCarthy J. Lisp 1.5 Programmer's Manual. MIT Press, Cambridge,
Massachusetts, 1963.
Steele, G.L. Common Lisp – the Language (Second Edition). Digital
Press, Hanover, Massachusetts, 1990.
The Haskell Platform [Электронный ресурс]. – Электрон. дан. –
URL: https://www.haskell.org/platform (дата обращения: 25.04.2015)
Word-to-CHM Converter 2007 [Электронный ресурс]. – Электрон.
дан. – URL: http://word-to-chm-converter-2007.soft112.com/
(дата обращения: 19.10.2015)
Download