Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис» Министерство образования и науки Российской Федерации УДК 519.682 ББК 32.973-018я73 Омский государственный университет им. Ф.М. Достоевского Ч 188 Рекомендовано к изданию в качестве учебного пособия учебно-методическим советом математического факультета Рецензенты: канд. физ.-мат. наук, доцент С.В. Зыкин, канд. физ.-мат. наук, доцент А.Л. Агафонов Чанышев О.Г. Ч 188 Основные элементы языка программирования Icon: Учебное пособие. – Омск: Изд-во ОмГУ, 2004. – 55 с. О.Г. Чанышев ISBN 5-7779-0523-4 Основные элементы Пособие является первой публикацией на русском языке, языка программирования Icon посвященной мощному средству быстрой разработки программ для систем ИИ, особенно для автоматического анализа естест- венно-языковых текстов – языку Icon. В основу положена кни- Учебное пособие га Thomas W. Christopher «Icon Programming Language Hand- book», однако данное пособие – не перевод. Автор опирается на собственный опыт работы с языком; примеры программ в подавляющем большинстве оригинальны. Для студентов математического факультета. УДК 519.682 ББК 32.973-018я73 Изд-во Омск © Чанышев О.Г., 2004 ОмГУ 2004 ISBN 5-7779-0523-4 © Омский госуниверситет, 2004 2 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис» ОГЛАВЛЕНИЕ 10. Процедуры 10.1. Вызов процедур.............................................................................36 Введение.........................................................................................................5 10.2. Выход из процедуры......................................................................38 1. О синтаксисе, переменные, декларации............................................11 11. Основные функции для работы с файлами.....................................39 2. Генераторы 12. Немного о совыражениях – coexpression..........................................41 2.1. Every, to, every do.............................................................................13 13. Графический интерфейс 2.2. !e – генерация элементов.................................................................15 13.1. Атрибуты окна...............................................................................44 2.3. Оператор & – and.............................................................................15 13.2. Текст – запись в окно и чтение из................................................46 2.4. Backtracking и неуспех....................................................................15 13.3. Диалоги...........................................................................................47 2.5. Проверка на &null............................................................................16 13.4. Создание меню...............................................................................48 2.6. Альтернатива |..................................................................................16 13.5. Чтение и запись изображений......................................................50 2.7. Повторы с ограничением. Функция генерации Заключение..................................................................................................51 последовательностей....................................................................................17 Задачи для закрепления материала........................................................52 2.8. Coevaluation – «Совычисления».....................................................17 Список используемой литературы..........................................................54 2.9. Множественные арифметические операции сравнения...............18 3. Управляющие структуры 3.1. if.........................................................................................................19 3.2. case of................................................................................................19 3.3. while do.............................................................................................19 3.4. until do...............................................................................................20 3.5. repeat – повторять до бесконечности.............................................20 4. Символьные множества 4.1. Операции с множествами символов...............................................21 4.2. Принадлежит ли символ множеству? Функция any.....................21 5. Строки .....................................................................................................22 5.1. Подстроки.........................................................................................22 5.2. Операторы для работы со строками...............................................23 5.3. Функции для преобразования строк...............................................23 5.4. Функции сканирования строк.........................................................24 5.5. Более мощные варианты функций сканирования.........................27 6. Списки 6.1. Создание списков.............................................................................29 6.2. Индексированный доступ к элементам списков...........................29 6.3. Операции со списками.....................................................................29 6.4. Функции для работы со списками..................................................30 6.5. Списки как стеки или очереди........................................................30 7. Таблицы...................................................................................................31 7.1. Сортировка таблиц..........................................................................32 7.3. Некоторые другие функции............................................................33 8. Множества...............................................................................................34 9. Записи.......................................................................................................35 3 4 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис» Введение жения Icon'а – генераторы». Выражения генерируют последова- тельности значений, используя «бэктрекинг». В предисловии к одной из лучших монографий, посвящен- Пример использования генератора: ных Прологу [1], И. Братко писал: «В средние века знание латин- procedure main() ского и греческого языков являлось существенной частью образо- L:=["mmm","nnnnn","oooooo"] # Список строк вания любого ученого. Ученый, владеющий только одним языком, every writes(" ",! L) неизбежно чувствовал себя неполноценным, поскольку он был end лишен той полноты восприятия, которая возникает благодаря воз- Выход: mmm nnnnn oooooo можности посмотреть на мир сразу с двух точек зрения. Таким же Icon не является строго типизированным (тип имеют кон- неполноценным ощущает себя сегодняшний исследователь в об- станты, но не переменные). Это и не плохо и не хорошо, но чаще ласти искусственного интеллекта, если он не обладает основатель- всего удобно. Будьте внимательны и следуйте модульному стилю ным знакомством как с Лиспом, так и с Прологом – этими двумя программирования. основополагающими языками искусственного интеллекта, без Icon обладает мощными встроенными типами данных для знания которых невозможен более широкий взгляд на предмет организации сложно структурированной информации: ассоциатив- исследования». ные таблицы, списки, записи, множества по модулю 2 (автомати- С полной уверенностью могу добавить к этим языкам и Icon, чески исключающие дублирование), символьные множества. Поч- который прост и могуч во многом потому, что наследует идеоло- ти любой тип из этого перечня может быть элементом другого ти- гию мощного семейства языков SNOBOL, первые представители па. Например, элементами таблиц могут быть списки. Списки мо- которых появились еще в начале 60-х. Название языка не имеет гут состоять из записей и т. п. Только не надо специально услож- ничего общего с «иконками», а является сокращением от слова нять структуры. Все должно быть ЦЕЛЕСООБРАЗНЫМ. («Красо- «iconoclastic» (иконоборец) [1], используемом в смысле борьбы с та – это целесообразность» – Иван Ефремов (?)). конформизмом в разработке языков программирования. Процедуры в Icon'е «относятся к величинам первого класса Настоящий материал следует рассматривать как введение в (first class values, что означает возможность присваивания перемен- программирование на Icon’е. Это – не учебник по программирова- ным значений самих процедур, а не результатов их выполнения). нию, он рассчитан на студентов, уже имеющих опыт программи- В Icon встроен механизм «совыражений» (co-expression) – рования на Си или Паскале. «Императивная» внешность Icon’а почти независимо выполняющихся частей программы, что дает способствует быстрому усвоению языка. Простота синтаксиса, возможность как создавать классические сопрограммы, так и реа- небольшое, но функционально мощное множество структур дан- лизовывать произвольные псевдопараллельные алгоритмы. ных делают его очень удобным языком быстрого прототипирова- Icon поддерживает автоматическую конверсию типов. ния, т. е. за более короткое время, чем программирование на Си, Icon включает кросс-платформенные графические возмож- можно написать и отладить программу, при помощи которой про- ности. веряются основные идеи концепции. Мой собственный опыт подтверждает, что программы на Сохраняя внешне стиль императивных языков, на самом де- Icon'е быстро разрабатываются, быстро и надежно работают. Я ле Icon имеет много инструментов, роднящих его с языками логи- даже стал задумываться: а не изменить ли моей старой любви – ческого программирования. Например, «бэктрекинг», или генера- Prolog'у?! (Тем более что Icon распространяется свободно (не для торы. Christopher [2] пишет: «Самое большое различие между коммерческого использования!) и Вы можете свободно распро- Icon'ом и другими языками программирования – это то, что выра- 5 6 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис» странять собственные выполняемые модули (exe – файлы), в от- "The vertical bar, "|", read "«or»", looks like a binary operator личие от PDC Visual Prolog.) but does not behave like one". Приведем несколько «программулек» для иллюстрации: Другой пример: символ "\" в выражениях "\x" и "|(z to y)\x" procedure main() обозначает различные операторы (в первом случае проверяется, #Перезапись файла имеет ли значение переменная x, а во втором – является ли огра- f:=open("x.txt","r")|stop("cannot open x.txt") ничителем генерируемых значений). f2:=open("y.txt","w")|stop("cannot open y.txt") У Icon’а есть сложности с кириллицей. Он «не понимает» # Классический стиль кириллические имена файлов при стандартном открытии while s:=read(f) do write(f2,s) f:=open(“имя_моего_файла”,”rt”) либо когда имя файла передается close(f) в командной строке close(f2) icon_prog.exe имя_моего_файла procedure main(args)) end f:=open(args[1],”rt”) ………………………. В стиле Icon'а подчеркнутые элементы кода заменит выра- end жение Чтобы обойти эту сложность, следует работать в графиче- every write(f2,!f) ском режиме и обращаться к соответствующему «диалогу». link graphics Большинство проблем при парсировании кириллического procedure main() текста Вы можете обойти, создав собственное множество симво- # Простейший вариант открытия графического окна: лов: WOpen("size=400,300") | stop("can't open window") allRus:='АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЪЫЭ Font("Times New Roman,18") # Устанавливаем шрифт ЮЯабвгдеёжзийклмнопрстуфхцчшщьъыэюя' L:=["Линия 1","Линия 2","Линия 3"] И при необходимости можете создать объеденное множество: case SelectDialog("Выберите линию",L,L[1]) of allLetters:= &ascii++allRus { ……………………………………………………………….. "Okey": Теперь несколько слов о математических возможностях { Icon’а (которые меня не очень интересуют и в дальнейшем изло- GotoRC(1,1) жении специально не рассматриваются). Язык обладает вполне WWrite(dialog_value) # Печатаем выбранную строку достаточным набором операторов и функций для того, чтобы быть WDone() алгоритмически полным и в «вычислительном» смысле. Он рабо- } тает с целыми и реальными числами. Имеет специальные средства "Cancel": {} для манипулирования коплексными и рациональными числами. } Бинарные операторы: end * – умножение / – деление Может быть, единственное, что мне не нравится в Icon'е, это % – остаток (5%2=1) семантическая многозначность операционных символов (разре- + – сложение шаемая контекстно). Вот цитата из Cristophera [2, с. 41]: - – вычитание 7 8 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис» Следует помнить, что звездочка (*), используемая как пре- и Idol (объектно-ориентированное раширение Icon. – О.Ч.), рас- фиксный оператор, возвращает длину объекта. пространяемые в исходных текстах. В любом случае изучение Информацию о языке, а также дистрибутивы самого языка этих языков доставит удовольствие и вооружит вас мощнейшим можно получить по адресу http://www.cs.arizona.edu/icon. Устано- инструментом как быстрого прототипирования сложных про- вите Icon (и «пропишите»!). Для написания простых программ грамм, так и "реактивного" создания целого класса очень нужных (файл с исходным текстом должен иметь расширение.icn) можете приложений, для которых любой другой инструментарий не под- пользоваться любым текстовым редактором. ходит из-за слишком больших трудозатрат». Если у Вас сложный проект, состоящий из нескольких icn- файлов, то предварительно компилируются отдельные части про- граммы: wicont –c <имя_файла>.icn Затем для компиляции и получения исполняемого модуля: wicont <имя_главного_файла>.icn Главный icn-файл содержит procedure main(…) и деклара- тивы link с именами файлов проекта: link <имя_1>.icn ………………… link <имя_N>.icn …………………. procedure main(…) …… end procedure p1(…) ……… end procedure pn(…) ……… end Некоторые книги на английском языке доступны в pdf- формате по адресу http://www.cs.arizona.edu/icon/books.htm. Лите- ратурные источники по данной теме на русском языке мне не из- вестны, за исключением сотни строк в статье А. Зубинского [2], цитатой из которой я и завершу введение: «Заинтересовавшимся… можно порекомендовать отличную online-версию книги Icon Programming Language Handbook Томаса Кристофера (пригодный к чтению на любых платформах pdf-формат) и сами системы Icon 9 10 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис» 1. О синтаксисе, переменные, декларации global – создание переменной, известной всем процедурам (global x,y). Возможно, Вы уже обратили внимание на то, что синтаксис procedure <имя_процедуры> – начинает объявление проце- языка Icon очень прост. Операторы языка разделяются либо сим- дуры. волом перевода строки, либо точкой с запятой (;). Например: record <имя_записи>(<список_имен_полей>) – создает every {writes(" ",1 to 5);writes(" ",6 to 10)} структуру данных, называемых «записью» (record r(x,y,z)). или link <имя_внешней_процедуры> указывает редактору, что every данная программа использует внешнюю процедуру. { invocable <имя_процедуры> – позволяет обращаться к про- writes(" ",1 to 5) цедуре по имени-строке ("f"(x)). writes(" ",6 to 10) Декларации global, record, link, invocable должны появляться } только в начале программы (в преамбуле), до первого объявления Запятая используется для разделения элементов в разного какой-либо процедуры. рода перечислениях. Группы операторов, например, в выражениях Договоримся на дальнейшее, что, следуя Christopher'у, ла- if {} then {} else тинской e или ei, где i – целое, будем обозначать произвольные ограничиваются фигурными скобками. Квадратные скобки выражения. [] служат, преимущественно, для индексирования выражений (L[3] обозначает третий элемент некоторой структуры). В круглые скобки обычно заключается список параметров или выражения в «совычислениях» – coavaluation. Объявления процедуры начина- ются со слова procedure, за которым следует либо main(...), либо <имя_процедуры>(p1,...,pn) с формальными параметрами. Процедура заканчивается словом "end". Процедуры не могут быть вложенными. Все ключевые слова пишутся с маленькой ла- тинской буквы. Имена переменных могут состоять из латинских букв, цифр и знаков подчеркивания. Имена переменных, буквы которых на- браны в различных регистрах – разные имена (naMe и name, Name – разные имена). Декларации local – создание переменной, известной только внутри про- цедуры и существующей до выхода управления из данной проце- дуры (local x,y). static – создание переменной, известной только внутри про- цедуры и сохраняющей последнее присвоенное значение в тече- ние выполнения программы в целом (static x,y). 11 12 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис» 2. Генераторы Оператор to может генерировать серию значений. Напри- мер, в случае 100 to 103 мог бы сгенерировать значения 100, 101, Генераторами называются операторы (и выражения), произ- 102, 103, если ему это позволят. водящие множество значений в контексте генерации. Чтобы по- В случае write(10 to 20) печатается единственное значение нять, как работают генераторы, следует иметь в виду: 10. во-первых, общую для всех языков основную последова- Но every write(1 to 3) напечатает 123. тельность выполнения выражений – слева направо и сверху вниз с Вариант to by очевиден, by задает шаг. учетом приоритета операторов; Примеры: во-вторых, возврат назад для того, чтобы найти подвыраже- every i:=1 to 100 by 10 do write(i) ние, генерирующее более одного значения, взять новое значение и Выход: 1 повторить процесс. 11 Этот возврат с перебором называется бэктрекингом. Прото- 21 типами бэктрекинга являются различные конструкции, органи- .... зующие циклы. Бэктрекинг – «главный кит» Пролога, наряду с 91 подстановкой и унификацией. Он использует его, как нечто само every {writes(" ",1 to 5); writes(" ",6 to 10)} собой разумеющееся. Например, человек, знакомый только с Си, Выход: 1 6 7 8 9 10 не сможет понять, что предикат p: Но every (writes(" ",1 to 5), writes(" ",6 to 10)) p:-fact1(_,_,X,_),fact2(_,Y,_), X<Y,!,... дает на выходе: переберет все экземпляры фактов fact1, fact2, чтобы найти 1 6 7 8 9 10 2 6 7 8 9 10 3 6 7 8 9 10 4 6 7 8 9 10 5 6 7 8 9 10 первую их комбинацию, удовлетворяющую условию X<Y. В В данном случае (every (e1,e2)): Icon'е контекст перебора почти всегда должен быть указан явно, 1. После генерации первого из возможных значений выра- т. е. одного оператора, имеющего статус генератора, недостаточ- жения e1 но. Например: управление передается выражению e2. f:=open("myfile.txt,"rt") 2. e2 генерирует все возможные значения. .......................... 3. Затем e1 генерирует следующее значение и т. д. S:=!f # читается одна запись файла e1 и e2 могут быть успешными и неуспешными. Но выражение every(write(!f)) выведет построчно на экран every i:=1 to 5 do writes(" ",i) все записи (несколько ниже приведен пример кода в чисто «про- S:=4 логовском» стиле). every S<4 do writes(" ",17 to 18) Выход: нет выхода. 2.1. Every, to, every do Если же мы напишем every S<4, то будет напечатано число 17. every создает контекст, в котором может быть сгенерирова- но множество значений. В нижеследующем примере каждое вы- ражение в последовательности, за исключением последнего, гене- рирует не более одного значения. Последнее выражение генериру- ет столько значений, сколько позволяет контекст. 13 14 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис» 2.2. !e – генерация элементов end Выход: – исходная строка S и O'key с новой строки. Если e – некоторая структура, то !e берет первый элемент Проверка каждого символа на равенство символу перевода структуры, а в контексте генерации генерирует множество эле- строки порождает неуспех вплоть до последнего символа, что за- ментов этой структуры. ставляет первое подвыражение (sim:=!S) генерировать новые сим- Примеры: волы. В итоге напечатается строка S, а затем O'key. L:=[1,2];every writes(" ",!L).#Выход: 1 2 s:="cat";every writes(" ",!s).#Выход: c a t 2.5. Проверка на &null Бинарные операции, содержащие генераторы: every writes(" ",5 to 6)+(10 to 20)) Унарный оператор ‘\’ успешен, если его операнд имеет зна- напечатает 15 25 16 26 чение, отличное от &null, а ‘/’ – в противном случае, т. е. мы мо- жем написать 2.3. Оператор & – and if \x & \y then...". Если x не присвоено значение, мы не можем написать if e1&e2 ~x…, но должны написать if /x … . Этот оператор возвращает значение правого операнда и имеет наинизший приоритет. 2.6. Альтернатива | every i:=|seq(1,2)\3 & j:=|seq(2,2)\3 & i~= j & writes(" ",i+j) Выход: 3 5 7 5 7 9 7 9 11 Вертикальная черта ‘|’, читаемая как «или», смотрится как бинарный оператор, но появляется и в ином контексте. Выраже- 2.4. Backtracking и неуспех ние: e1 | e2 означает генерацию всех элементов e1, а затем – всех Перебор прекращается, когда перебирать уже нечего, и e2. управление переходит к следующему выражению. Например, на- procedure main() печать 12345 можно так (не рассматривая очевидный вариант local x,y,z write("12345")): every writes (1 to 5). L:=["Vera","Manja","Tanja"] Этот же результат можно получить, если использовать x:=1 встроенное в Icon выражение &fail, которое всегда порождает не- if (\x | \y) then z:=10 успех. (writes(" ",!L) | write(" ",z)) write (1 to 5) + &fail. every (writes(" ",!L) | write(" ",z)) write("\n","O'key") #while (writes(" ",!L)) | write(" ",z)) Знак ‘+’ нужен только для конструирования синтаксически end правильного выражения, т. е. контекст генерции задается "неуспе- Выход: Vera Vera Manja Tanja 10 хом". Если раскомментировать выражение перед end, то получим Тогда мы можем использовать чисто «прологовский» стиль: бесконечную печать слова Vera. procedure main() S:="tak pit hochetsa, chto perenochevat negde\n" (sim:=!S, writes(sim),sim=="\n") write("O'key") 15 16 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис» 2.7. Повторы с ограничением. Функция генерации после- every writes(" ",(!S,1 to 3)) довательностей write() every writes(" ",(!S & 1 to 3)) Генератор «с перезарядкой» |e позволяет генерировать все end значения e, затем происходит реинициализация и процесс повто- Выход: ряется бесконечно. q q q w w w e e e r r r t t t y y y u u u Чтобы избежать бесконечного повторения процесса, исполь- 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 зуется ограничитель числа повторений: |e\n. 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 Например: every |(writes(7))\7 выведет 7777777, так же, как и every (writes(|7\7)), и every i:=1 to 7 do writes(7). 2.9. Множественные арифметические операции сравне- ния Специальная функция seq() предназначена для генерации бесконечных рядов значений Такие операции, как a<b<c, Christopher относит к генерато- seq() генерирует 1,2,3,............. рам. В связи с этим следует сказать об обычном в Icon'е програм- seq(i) генерирует i,i+1,i+2........ мистском трюке. Если мы ходим выбрать наименьшее из x и y, то: seq(i,j) генерирует i+j,i+2j,i+3j.. x:=x>y или x>:=y every writes(" ",seq(2,2)\5) выведет 2 4 6 8 10 как и every writes(" ",seq(2,2))\5 2.8. Coevaluation – «Совычисления» В общем виде совычисления представляются так: e0(e1,e2,...,eN), где e0 – выражение, вычисляющее номер выражения в скоб- ках, которое генерирует значения, и может быть переменной, зна- чение которой есть целое число, вычисляемое где-то в другом месте программы. Действия остальных заключаются в активации бэктрекинга. «Вырожденная» форма: (e1,e2,...,eN) эквивалентна N(e1,e2,...,eN) или (e1&e2&...&eN). Пример: procedure main() K:=1 S:="qwertyu" every writes(" ",K(!S,1 to 3)) write() 17 18 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис» 3. Управляющие структуры 3.4. until do until e1 do e2 3.1. if... Эквивалентно while not e1 do e2 Пример: Печать чисел Фибоначчи if e1 then e2 else e3 procedure main() if e1 then e2 local i,j e1 может генерировать не более одного значения i:=1;j:=1 e3 могут генерировать столько значений, сколько позволяет until i>100 do {write(i,j);i+:=j;i:=:j} контекст. end 3.2. case of 3.5. repeat – повторять до бесконечности. case e1 of i:=1 { repeat e2 : e3 { if i<10 then {write("i меньше 10");i:=i+1} else break e4 : e5 } ... e2n : e2n+1 default : e2n+2 } 3.3. while do while e1 do e2 while e1 Генерируется одно значение e1, и если НЕ ЛОЖЬ, то вы- полняется e2. Пример: i:=0 while i<2 do {writes(" ",i);i+:=1} Выход: 0 1 В следующем примере будут бесконечно «печататься» на экране вводимые Вами строки символов: while write(read( )) 19 20