Госкомитет России по связи и информатизации ПОВОЛЖСКАЯ ГОСУДАРСТВЕННАЯ АКАДЕМИЯ ТЕЛЕКОММУНИКАЦИЙ И ИНФОРМАТИКИ
Одобрено...
21 downloads
173 Views
377KB 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
Госкомитет России по связи и информатизации ПОВОЛЖСКАЯ ГОСУДАРСТВЕННАЯ АКАДЕМИЯ ТЕЛЕКОММУНИКАЦИЙ И ИНФОРМАТИКИ
Одобрено Методическим советом ПГАТИ 3.04.1998
МЕТОДИЧЕСКИЕ УКАЗАНИЯ к выполнению лабораторных работ " ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ АВТОЛИСП"
Автор-составитель:
КУЛЯС О.Л., к.т.н., доцент
Редактор:
АКЧУРИН Э.А., к.т.н., доцент
Рецензент:
ТЯЖЕВ А.И., д.т.н., профессор
Самара 1998
2 ВВЕДЕНИЕ Лабораторный цикл входит в дисциплину "Функциональное программирование" специальности 220400 и включает в себя четыре четырехчасовые работы по изучению языка программирования АВТОЛИСП. Каждая лабораторная работа включает разделы подготовки к ее выполнению с перечнем контрольных вопросов, задание на выполнение работы и краткие теоретические сведения по изучаемым разделам. Приведен список рекомендуемой для подготовки к выполнению работ литературы.
РЕКОМЕНДУЕМАЯ ЛИТЕРАТУРА 1. Лавров С.С., Силагадзе Г.Е. Автоматическая обработка данных. Язык ЛИСП и его реализация. М., Наука, 1978. 2. Хендерсон П. Функциональное программирование. Применение и реализация. М., Мир, 1983. 3. Филд А., Харрисон П. Функциональное программирование. М., Мир, 1993. 4. Хювенен Э., Сеппянен И. Мир ЛИСПа. ,т.1 и 2 . М., Мир, 1990. 5. Уинстон П. Искусственный интеллект. М., Мир, 1990 6. Иванов О.Н., Чайкин А.А., Шевченко В.Н. Язык программирования AutoLISP Release 10, 11. М., TRINIKA Ltd, 1992. 7. Гладков С.А. Программирование на языке АВТОЛИСП в системе САПР АВТОКАД. М., Диалог-МИФИ, 1991. 8. Кречко Ю.А., Полищук В.В. АВТОКАД: курс практической работы. М., Диалог МИФИ, 1994. 9. Геснер Р., Бойс Дж. АВТОКАД для начинающих. Казань, Гармония, 1993. 10.Кречко Ю.А., Полищук В.В. АВТОКАД 13: новые возможности. М., Диалог МИФИ, 1996. 11.Конспект лекций по дисциплине "Функциональное программирование".
3
ЛАБОРАТОРНАЯ РАБОТА N1
ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ЯЗЫКЕ АВТОЛИСП
1. Подготовка к работе Изучить по лекциям и методической разработке вопросы, связанные с лексикой, особенностями представления данных и выражений на АВТОЛИСПе. Изучить функции присвоения значений переменным, функции создания списков и основные функции работы с ними. Изучить основные математические функции АВТОЛИСПа. 2. Контрольные вопросы 1. Активизация АВТОЛИСПа и основные приемы работы ним. 2. Основные лексические соглашения АВТОЛИСПа. 3. Типы данных в АВТОЛИСПе. 4. Присвоение значений переменным. Функции SET и SETQ. 5. Понятие списка. Создание списков в АВТОЛИСПе. 6. Элементарные селекторы в АВТОЛИСПе. Функции CAR и CDR. 7. Правила записи S-выражений в АВТОЛИСПе. 8. Базовые арифметические функции АВТОЛИСПа. 9. Базовые функции отношения. 10. Базовые тригонометрические функции. 3. Задание на выполнение работы 1. Загрузить АВТОКАД и выйти в его графический редактор, обеспечив при этом работу АВТОЛИСПу. 2. Определить версию АВТОЛИСПа, используя функцию (VER). Обратить внимание на действия клавиш "пробел" и "ENTER". Вывести на экран и просмотреть содержимое имен функций АВТОЛИСПа, хранящихся в переменной ATOMLIST: !atomlist . 3. Присвоить переменным значения в соответствии с таблицей, используя функции SET и SETQ. После присвоения проверить значения переменных функцией !<переменная>.
4 имя переменной
значение
a b c d e f g h l m n e1 f4 gh
12 5 -8 6,5 - 4,25 " C3" nil " -15 * 10^2 " 11,25 * 10^5 " ups " nil (car) a*b-c e/25,3
4. Определить тип созданных переменных с помощью функций АВТОЛИСПа ATOM, BOUNDP, LISTP, TYPE . 5. Проверить выполнение математических функций АВТОЛИСПа для выражения состоящего из аргументов a, b, c, d. 6. Создать списки S, G1 и QL из следующих элементов: S
G1
QL
+ 2,9 * 10е3
(y1)
(25 -8 *5)
(- 54)
12,5
"IBM"
0, 255
(- 9*5)
6.28
"key"
"a - b"
"pi"
()
(- 4 0.28 0.6)
()
(ab k (d m))
"12/ 3"
55
(12 ("dog" "cat") NN)
-45
(e F (xy) mn)
"mouse" 7. Последовательно извлечь из созданных списков S, G1 и QL - первые элементы - вторые элементы - третьи элементы
5
- четвертые элементы. Просмотреть как изменились после этого списки S, G1, QL. 8. Выйти из АВТОКАДа командой END. 9. Составить отчет, который должен содержать все вводимые функции АВТОЛИСПа и возвращаемые результаты по всем пунктам задания. 4.Общие сведения Язык программирования LISP (LISt Processing - обработка списков) впервые предложен Дж. Маккарти в 1960 г.. Название языка хорошо подчеркивает основную область его применения - решение задач нечисленного характера. В виде списков удобно представлять алгебраические выражения, графы, элементы конечных групп, множества, правила и другие сложные объекты. Списки являются наиболее гибкой формой представления информации в памяти современных ЭВМ. LISP является функциональным языком - в основу которого положено понятие функции. Все вычисления, преобразования и управления программы в этих языках осуществляются с помощью элементарных (встроенных) функций или функций, определяемых программистом при написании программы. Программа на LISP является суперпозицией некоторых функций и, в свою очередь, может быть использована как функция другими программами. LISP отличается от обычных языков программирования оригинальным решением одной из проблем исскуственного интеллекта - теории рекурсии. Поскольку эта проблема возникает во многих отраслях знаний, LISP может использоваться в таких разных областях, как экспертные системы, символическая алгебра (символьные методы), разработка СБИС, машинное зрение, разработка архитектуры вычислительных систем и другие. AutoLISP - это специально созданный для AutoCAD диалект LISPа, полученный в результате изменения языка XLISP. Он идеально подошел для АВТОКАДа, поскольку позволяет программно работать с объектами, справочными таблицами, считывать и записывать файлы. Т.е. он является прямым и единственным окном внутрь АВТОКАДа. СОГЛАШЕНИЯ ПО ЛЕКСИКЕ В AutoLISP для ввода программ или данных приняты следующие лексические соглашения: - имена символов могут состоять из любой последовательности литер (печатных знаков), исключая следующие: (, ), ., ', ", ;.
6 - следующие литеры вызывают прерывание имени переменной или константы: (, ), ', ", ;, пробел, конец файла. - выражения могут занимать несколько строк. - несколько пробелов между именами эквивалентны одному пробелу. - имена функций и символов безразличны к регистру на котором они набираются. Имена символов не могут начинаться с цифры. Нельзя использовать в качестве имен имена функций АВТОЛИСПа. (Все имена функций АВТОЛИСПа, а также имена, созданные пользователем, храняться в переменной ATOMLIST. Вывести ее на экран можно из командной строки, набрав: !atomlist . - целые константы могут начинаться с необязательных литер "+" или "-". Значения целых чисел должны находиться в пределах от -32768 до +32767. - Действительные константы состоят из одной или более цифр, за которыми следует десятичная точка, за которой в свою очередь следует одна или более цифр. Далее в необязательном порядке могут следовать латинские литеры "e" или "E" и показатель степени числа 10. Таким образом: .34 56. -2.е2 - неверные записи 0.34 56.0 -2.0е2 - верные записи. - Строковые константы (литералы) - это последовательность литер взятая в кавычки. - Знак апострофа может быть использован как короткая запись функции QUOTE. 'foo эквивалентно (quote foo). - В программу могут быть введены комментарии. Они начинаются с литеры ";" и продолжаются до конца строки. - Точечная пара - это два элемента, каждый из которых является именем символа, числовой константой или литералом, заключенных в круглые скобки и разделенные разделителями. В качестве разделителей используются круглые скобки или пробелы. - pi, t, nil - обозначают соответственно число ПИ, символ логической истины и символ "пусто". Типы данных в AutoLISP Поскольку LISP предназначен в первую очередь для обработки символьной информации числа в нем играют не главную роль. Основные типы данных в нем называются "атом" и "точечная пара". Атом - это переменные любого из простых типов. AutoLISP в отличии от других
7
диалектов LISP имеет два специфических типа данных, это "имена примитивов" и "наборы" системы проектирования AutoCAD. В AutoLISP имеются следующие типы атомов: - списки - набор разделенных пробелами атомов и/или списков, заключенных в круглые скобки. - числа: целые числа - это положительные и отрицательные целые числа (без дробей и десятичных точек) и действительные числа - это проложительные и отрицательные числа с десятичной точкой. - литералы (строковые переменные) - последовательность литер взятая в кавычки. - символы - переменные, в которых хранятся не значения, а ссылки на другие переменные. - файловые дискрипторы - описатели файлов. - имена примитивов системы AutoCAD - переменные в которых хранится индекс однозначно соответствующий примитивам чертежа AutoCAD. - наборы системы AutoCAD - встроенные функции - переменные , посредством которых осуществляется обращение к стандартной библиотеке функций. В AutoLISP существует возможность проверить является ли переменная атомом. Для этого используется функция (atom<переменная>). Если да - возвращается T (истина), если нет - nil. Далее можно определить является ли атом пустым списком с помощью функциии (boundp <атом> ). в противном Возвращается nil если атом имеет значение nil, и T случае (т.е. если атом имеет какое то значение или ссылку). Для определения того, является ли переменная списком, существует функция (listp <переменная>). Возвращает Т, если переменная список, иначе - nil. Наконец в AutoLISP можно определить тип данных объекта с помощью функции (type< объект>). При этом возвращается как символ тип данных объекта: INT - целые величины REAL - числа с плавающей точкой STR - строковые константы FILE - дескрипторы файлов SYM - символы LIST - списки и функции пользователя SUBR - встроенные функции AutoLISP ENAME - имена примитивов AutoCAD
8 PICKSET PAGETB -
наборы примитивов AutoCAD таблицы диспетчера страниц.
Выражения AutoLISP Любая управляющая конструкция AutoLISP содержит функции встроенные или созданные пользователем. Причем в списке функция должна стоять на первом месте. Выражения (S-выражения) AutoLISP это список, первым элементом которого является функция. Любая программа на LISP состоит из выражений и сама является выражением. Основные свойства выражений заключаются в следующем: - Каждая открывающая скобка должна иметь закрывающую. - Сразу после открывающей скобки должно стоять имя функции, выполняемой при вычислении. - Следующие за именем функции аргументы отделяются пробелом от функции и друг от друга. Дополнительные пробелы игнорируются , поэтому выражение может занимать несколько строк. - Каждое выражение вычисляется и результат возвращается. - С логической точки зрения любое возвращаемое значение может быть истинно или ложно. Итак, выражения AutoLISP имеют вид: (функция аргумент1 аргумент2 ... аргументN) Основы программирования на языке АВТОЛИСП Присвоение значений переменным Присвоение значений переменным осуществляется двумя функциями SET и SEYQ. В зависимости от значения, присваемого переменной, определяется ее тип. Значения переменных сохраняются до конца сеанса работы или до задания новых значений. Функция SET (установить) имеет формат (set '<символ> <выражение>). Данная функция присваивает символу (где символ - имя переменной) значение выражения и возвращает это значение. Использование имени переменной с апострофом впереди равнозначно использованию специальной функции (quote <выражение>), которая возвращает выражение не выполняя его. Поэтому запись вида (quote cat) эквивалентна записи 'cat . Например: (set 'a 10.0) ;устанавливает в переменную А значение 10.0 и возвращает 10.0
9
(set (quote a) '(* b c d));устанавливает в переменную А выражение (* B C D) и возвращает (* B C D) Имя функции SETQ образовано как сокращение сочетания SET by Quote (присвоить по ссылке). Она позволяет в отличии от функции SET, обращаться не к самой переменной, а к ее значению. Эта функция является основной функцией присвоения в АВТОЛИСПЕ и имеет формат (setq <символ1> <выражение1> <символ2> <выражение2> ...). Данная функция устанавливает в символ1 значение выражения1, в символ2 значение выражения2 и т.д. и возвращает последнее выражение. Рассмотрим действие этой функции на примерах: (setq a 100 b 200) ;устанавливает в А значение 100, в В значение 200 и возвращает 200. (setq a '(c + d)) ;устанавливает в А выражение (C + D) и возвращает (C + D). (setq b 3 c 4 a (* b c) ; устанавливает в B значение 3, в C значение 4, в А значение произведения 12 и возвращает 12. Если функцией SETQ какой либо переменной было присвоено некоторое значение, то его можно использовать из командной строки АВТОКАДА. Для этого нужно в ответ на запрос напечатать ! и имя переменной: !a . Создание списков и работа с ними Функция LIST позволяет создать список. Она имеет формат: (list <выражение> ...) Данная функция берет любое число элементов <выражение>, создает из них список и возвращает его. Например: (list 14.75 12.4 0.0) ;создает список (14.75 12.4 0.0) и возвращает (14.75 12.4 0.0). В качестве элементов списка можно задавать не только конкретное значение, но и переменную любого типа, например: (list 12 'y 32.5 '(10.5 30) "cat"); создает список (12 y 32.5 (10.5 30) "cat") и возвращает (12 Y 32.5 (10.5 30) "CAT"). Для того чтобы к созданному списку можно было обратиться, следует присвоить его значение переменной используя функцию SETQ. Например, создадим список и присвоим его значение переменной SC: (setq sc (list 12 'y 32.5 '(10.5 30) "cat")). При программировании на LISP часто возникает необходимость извлечь один или несколько элементов списка. Для этого в АВТОЛИСПе существуют специальные встроенные функции, называемые элементарными селекторами.
10 Функция CAR позволяет извлечь первый элемент списка и возвращает его. Если список пуст, то возвращается NIL. Она имеет формат: (car <список>). Например: (car '(a b c)) возвращает A (car '(a b) c) возвращает (A B) (car '()) возвращает NIL. Функция CDR позволяет извлечь список без первого элемента и возвратить его. Если список пуст, возвращается NIL. Она имеет формат: (cdr <список>). Примеры: возвращает (B C) (cdr '(a b c)) (cdr '((a b) c)) возвращает (C) (cdr '()) возвращает NIL. Если в качестве аргументов этой функции задается точечная пара, то возвращается второй элемент точечной пары, список при этом не формируется. Например: (cdr '(a.b)) возвращает B (cdr '(1 . "Text")) возвращает "Text". Язык АВТОЛИСП допускает сцепление функций CAR и CDR до четырех уровней вложенности. Если дано: (setq x '((a b) c d), то вызов: (caar x) эквивалентен (car(car x)) и возвращает А (cdar x) эквивалентен (cdr(car x)) и возвращает (B) (cadar x) эквивалентен (car (cdr(car x))) и возвращает B (cadr x) эквивалентен (car (cdr x)) и возвращает C (cddr x) эквивалентен (cdr (cdr x)) и возвращает (D) (caddr x) эквивалентен (car (cdr (cdr x))) и возвращает D. Базовые функции языка АВТОЛИСП Автолисп располагает множеством предопределенных функций. Для вызова любой из них нужно задать ее имя (прописными или строчными буквами) в качестве первого элемента списка, последующими элементами которого являются аргументы функции (если они есть). Математические функции (+ <число> <число>...) Эта функция возвращает сумму всех своих аргументов. Она может работать как с целыми, так и с вещественными числами. Если все аргументы представляют собой целые числа, то и результат будет
11
целочисленным; если хотя бы один из аргументов является вещественным числом, все целые числа будут преобразованы в вещественные, и результат также будет вещественным. Например: (+ 1 2) возвращает 3 (+ 1 2 3 4.5) возвращает 10.500000 (+ 1 2 3 4.0) возвращает 10.000000 (- <число> <число>...) Эта функция вычитает второй аргумент из первого и возвращает полученнную разность. Если задается более двух аргументов, то из первого аргумента вычитается сумма всех остальных, от второго до последнего, и полученная разность возвращается в качестве результата. Если задан только один аргумент, функция возвращает результат вычитания этого аргумента из нуля. Функция может работать с целыми и с вещественными числами, используя обычные правила преобразования. Например: (- 50 40) (- 50 40.0 2) (- 50 40.0 2.5) (- 8)
возвращает возвращает возвращает возвращает
10 8.000000 7.500000 -8
( * <число> <число>...) Эта функция возвращает произведение всех своих аргументов, в качестве которых могут задаваться как целые, так и вещественные числа, преобразуемые по обычным правилам. Например: (* 2 3) (* 2 3 4.0) (* 3 -4.5)
возвращает 6 возвращает 24.000000 возвращает -13.500000
(/ <число> <число>...) Эта функция возвращает частное от деления первого числа на второе. Если задано более двух чисел, то первое число делится на произведение всех остальных, от второго до последнего, и частное от этого деления возвращается в качестве результата. Эта функция может использоваться с целыми и вещественными числами в соответствии со стандартными правилами. Например: (/ 100 2) (/ 100 2.0) (/ 100 20 2.0) (/ 100 20.0 2) (/ 100.0 20 2)
возвращает возвращает возвращает возвращает возвращает
50 50.000000 2.500000 2.500000 2.500000
12 (/ 100 20 2) (/ 135 360) (/ 135 360.0)
возвращает 2 возвращает 0 возвращает 0.375000
(= <атом> <атом>...) Эта функция реализует отношение "равно". Она возвращает "T" при численном равенстве всех своих аргументов, и "nil" в противном случае. В качестве аргументов можно задавать числа и строки. Например: (= 4 4.0) возвращает T (= 20 388) возвращает nil (= 2.4 2.4 2.4) возвращает T (= 499 499 500) возвращает nil (= "я" "я") возвращает T возвращает nil . (= "я" "ты") (/= <атом1> <атом2>) Эта функция реализует отношение "не равно". Она возвращает "Т", если аргументы численно не равны, и "nil" в противном случае. При количестве аргументов, большем двух, функция не определена. Примеры: (/= 10 20) возвращает Т (/= "ты" "ты") возвращает nil (/= 5.43 5.44) возвращает Т . (< <атом> <атом>...) Эта функция реализует отношение "меньше". Она возвращает "Т", если первый аргумент численно меньше второго, и "nil" в противном случае. При количестве аргументов, большем двух, "Т" возвращается в том случае, если каждый аргумент меньше своего правого соседа. Примеры: (< 10 20) возвращает T (< "b" "c") возвращает T (< 357 33.2) возвращает nil (< 2 3 88) возвращает T (< 2 3 4 4) возвращает nil . (<= <атом> <атом>...) Эта функция реализует отношение "меньше или равно". Она возвращает "Т", если первый аргумент численно меньше второго или равен ему, и "nil" в противном случае. При количестве аргументов, большем двух, "Т" возвращается в том случае, если каждый аргумент меньше своего правого соседа или равен ему. Примеры:
13
(<= 10 20) (<= "b" "b") (<= 357 33.2) (<= 2 9 9) (<= 2 9 4 5)
возвращает возвращает возвращает возвращает возвращает
T T nil T nil
(> <атом> <атом>...) Эта функция реализует отношение "больше". Она возвращает "Т", если первый аргумент численно больше второго, и "nil" в противном случае. При количестве аргументов, большем двух, "Т" возвращается в том случае, если каждый аргумент больше своего правого соседа. Примеры: (> 120 17) возвращает T (> "c" "b") возвращает T (> 3.5 1792) возвращает nil (> 77 4 2) возвращает T (> 77 4 4) возвращает nil . (>= <атом> <атом>...) Эта функция реализует отношение "больше или равно". Она возвращает "Т", если первый аргумент численно больше второго или равен ему, и "nil" в противном случае. При количестве аргументов, большем двух, "Т" возвращается в том случае, если каждый аргумент больше своего правого соседа или равен ему. Примеры: (>= 120 17) возвращает T (>= "c" "с") возвращает T (>= 3.5 1792) возвращает nil (>= 77 4 4) возвращает T (>= 77 4 9) возвращает nil . (1+ <число>) Эта функция возвращает <число>, увеличенное на 1; аргумент <число> может быть целым или вещественным. Примеры: (1+ 5) возвращает 6 (1+ -17.5) возвращает -16.500000 (1- <число>) Эта функция возвращает <число>, уменьшенное на 1; аргумент <число> может быть целым или вещественным. Примеры: (1- 5) возвращает 4 (1- -17.5) возвращает -18.500000
14 (abs <число>) Эта функция возвращает абсолютное значение аргумента, который может быть вещественным или целым. Примеры: (abs 100) возвращает 100 (abs -100) возвращает 100 (abs -99.25) возвращает 99.250000 (cos <угол>) Эта функция возвращает косинус аргумента <угол>, задаваемого в радианах. Примеры: (cos 0.0) возвращает 1.000000 (cos pi) возвращает -1.000000 (eval <выражение>) Функция возвращает результат вычислени аргумента <выражение>, который может быть представлен любым выражением Автолиспа. Если даны присваивания: (setq a 123) (setq b 'a) то (eval 4.0) возвращает 4.000000 (eval (abs -10) возвращает 10 (eval a) возвращает 123 (eval b) возвращает 123
(exp <число>) Эта функция возвращает "е" в степени, заданной аргументом <число> (натуральный антилогарифм). Возвращаемое значение представляет собой вещественное число. Например: (exp 1.0) возвращает 2.718282 (exp 2.2) возвращает 9.025013 (exp -0.4) возвращает 0.670320 (expt <основание> <степень>) Эта функция возвращает результат возведения <основания> в заданную <степень>. Если оба аргумента представлены целыми числами, результат также будет целочисленным, в противном случае результат будет вещественным. Примеры: (expt 2 4) возвращает 16 (expt 3.0 2.0) возвращает 9.000000
15
(log <число>) Эта функция возвращает в виде вещественного числа натуральный логарифм аргумента <число>. Например: (log 4.5) возвращает 1.504077 (log 1.32) возвращает 0.198850 (max <число> <число>...) Эта функция возвращает наибольший из своих аргументов, каждый из которых может быть целым или вещественным. Например: (max 4.07 -144) возвращает 4.070000 (max -88 19 5 2) возвращает 19 (min <число> <число>...) Эта функция возвращает наименьший из своих аргументов, каждый из которых может быть вещественным или целым. Например: (min 683 -10.0) возвращает -10.000000 (min 732 48 5) возвращает 2 (rem <число1> <число2>...) Эта функция возвращает остаток от деления <числа1> на <число2>, используя по обычным правилам как целые, так и вещественные числа. Примеры: (rem 42 12) возвращает 6 (rem 12.0 16) возвращает 12.000000 (rem 60 3) возвращает 0 (sin <угол>) Эта функция возвращает вещественное число, представляющее собой синус <угла>, заданного в радианах. Например: (sin 1.0) возвращает 0.841471 (sin 0.0) возвращает 0.000000 (sqrt <число>) Эта функция возвращает квадратный корень<числа>. Например: ( sqrt 4) возвращает 2.000000 (sqrt 2.0) возвращает 1.414214 Логические функции ( and <выражение>...) Эта функция возвращает результат логического умножения аргментов, представляющих собой выражения. Функция прекращает дальней-
16 шие вычисления и возвращает "nil", если какое-либо из выражений равно нулю, в противном случае возвращает "T". Если, например, выполнены следующие присваивания: (setq a 103) (setq b nil) (setq c "string") то (and 1.4 a c) (and 1.4 a b c)
возвращает Т возвращает nil
(or <выражение>...) Эта функция возвращает результат логического сложения аргументов <выражение>. Функция OR просматривает <выражения> слева направо в поиске <выражения>, отличного от нуля. Встретив такое <выражение>, функция прекращает дальнейшие вычисления и возвращает "Т". Если все <выражения> имеют значение "nil", функция возвращает "nil". Например: (or nil 45 '()) (or nil '())
возвращает возвращает
Т nil
(not<элемент>) Функция NOT используется для выполнения логического отрицания над операндом. Она возвращает Т, если <элемент > NIL, и NIL в том случае, если <элемент> определен (имеет какое-либо значение). Например: (setq pt1 '(10 20) pt2 nil pt3 '()) (not pt1) (not pt2) (not pt3)
возвращает NIL возвращает T возвращает T
(null <элемент>) Эта функция подобна функции NOT и возвращает "Т", если <элемент> имеет значение "nil", и "nil" в противном случае. Если даны присваивания: (setq a 123) (setq b "string") (setq c nil) то
17
(null a) (null b) (null c) (null '())
возвращает возвращает возвращает возвращает
nil nil T T
Функции сравнения выражений (eq <выражение1> <выражение2>) Эта функция устанавливает идентичность выражений <выражение1> и <выражение2>; выражения идентичны, если они связаны с одним и тем же объектом (скажем, с помощью функции "setq"). Функция EQ возвращает "Т", если выражения идентичны, и "nil" в противном случае. Обычно эта функция используется для установления идентичности двух списков. Например, если даны присваивания: (setq f1 '(a b c)) (setq f2 '(a b c)) (setq f3 f2) то (eq f1 f3) возвращает nil (f1 и f3 -- разные списки!) (eq f3 f2) возвращает T (f3 и f2 -- это один и тот же список) Смотрите также описание функции EQUAL. (equal <выражение1> <выражение2>) Эта функция устанавливает, равны или нет аргументы <выражение1> и <выражение2>; выражения равны между собой, если их вычисление приводит к одному и тому же результату. Если даны следующие присваивания: (setq f1 '(a b c)) (setq f2 '(a b c)) (setq f3 f2) то (equal f1 f3) возвращает Т (вычисление f1 и f3 дает одинаковый результат) (equal f3 f2) возвращает Т (f3 и f2 -- это один и тот же список) Заметим, что для одних и тех же списков отношение EQUAL может выполняться, а отношение EQ - нет. Если для каких-либо атомов выполняется отношение EQUAL, то для них выполняется и отношение EQ. Кроме того, если для двух списков или атомов выполняется отношение EQ, то для них выполняется и отношение EQUAL.
18
ЛАБОРАТОРНАЯ РАБОТА N2
СОЗДАНИЕ ФУНКЦИЙ ПОЛЬЗОВАТЕЛЯ НА ЯЗЫКЕ АВТОЛИСП 1. Подготовка к работе Изучить по лекциям и методической разработке вопросы связанные с лексикой, особенностями представления данных и выражений на АВТОЛИСПе. Изучить основные математические функции АВТОЛИСПа. Изучить функцию DEFUN и основные функции ввода -вывода для организации диалога с пользователем. 2. Контрольные вопросы 1. Типы данных в АВТОЛИСПе. 2. Пользовательская функция DEFUN. Локальные переменные и аргументы. 3. Интерактивные процедуры и семейство функций GETxxx. 4. Функция GETINT. 5. Функция GETREAL. 6. Функция GETKWORD. 7. Функция INITGET. 8. Вывод информации в интерактивных процедурах. 9. Правила записи S- выражений в АВТОЛИСПе. 10. Арифметические функции и правила записи арифметических выражений. 3. Задание на выполнение работы 1. Загрузить АВТОКАД и выйти в его графический редактор, обеспечив при этом работу АВТОЛИСПу. 2. Создать функцию ANGLE производящую перевод вводимых в градусах углов в радианы по формуле: a*pi/180, где а - угол в градусах, a>0. 3.Создать функции SINS, COSN, TUN вычисляющие синус, косинус и тангенс положительных углов, вводимых в градусах.
19
4.Создать функцию LG, вычисляющую десятичный логарифм вводимого числа по формуле: LG X= LN X/LN 10 при X /= 0. 5.Создать функцию CBR вычисляющую корень N-ой степени из вводимого числа при N>=0. 6.Создать функцию STEP, производящую возведение вводимого числа X в дробную степень, с показателем M/N. При создании функций использовать диалог в виде запросов и подсказок, созданный функциями семейства GET и INITGET. 7. Выйти из АВТОКАДа командой END. 9. Составить отчет, который должен содержать все вводимые функции АВТОЛИСПа и возвращаемые результаты по всем пунктам задания. 4.Общие сведения Создание функций пользователя в АВТОЛИСПе Для определения новых функций используется специальная встоенная функция DEFUN (DEFine FUNction - определить функцию). Эта функция создает свою собственную замкнутую область локальных переменных. Формат этой функции: (defun <имя> <список аргументов> <выражение>...) С помощью функции DEFUN определяется функция с именем, задаваемым аргументом <имя> (заметим, что имя функции заключается в кавычки автоматически, и пользователь не должен делать это "вручную". За аргументом <имя> следует <список аргументов> (возможно, пустой); за списком может следовать косая черта, а за ней - одно или несколько имен локальных переменных определяемой функции. Косая черта должна быть отделена по крайней мере одним пробелом и от последнего аргумента определяемой функции (если таковые есть), и от первой локальной переменной. При отсутствии аргументов и переменных после имени определяемой функции задается пустой список, заключенный в круглые скобки. Например: (defun имя (x y)...)
;определяемая функция "имя" имеет ;два аргумента (defun имя (/ a b)...) ;две локальных переменных (defun имя (x / temp)...) ;один аргумент и одна локальная ;переменная (defun имя ()...) ;нет ни аргументов, ни локальных ;переменных После аргументов и локальных переменных могут задаваться выражения, котрые нужно вычислить при исполнении определяемой функции.
20 Сама функция DEFUN возвращает имя определенной пользователем функции. При вызове пользовательской функции она вычисляет <выражения> и присваивает результаты аргументам из <списка аргументов>. При использовании локальных переменных значения, который они имели вне функции, сохраняются. Пользовательская функция возвращает результат вычисления последнего выражения. Результаты вычисления предыдущих выражений не сохраняются. Примеры: (defun плюс10 (X) (+ 10 X) ) (плюс10 5) (плюс10 -7,4)
возвращает возвращает возвращает
ПЛЮС10 15 2.600000
(defun точки (x y / temp) (setq temp (strcat x "...")) (strcat temp y) ) (точки "а" "б") (точки "из" "в")
возвращает возвращает возвращает
ТОЧКИ "а...б" "из...в"
ПРИМЕЧАНИЕ: Никогда не задавайте имя встроенной функции в качестве аргумента <имя>, иначе возможность доступа к этой функции будет утрачена. Организация ввода информации в интерактивных процедурах Для ввода различных типов данных в АВТОЛИСПЕе существует семейство функций GETxxx. Эти функции могут иметь в качестве аргумента произвольную строковую переменную, в которой может содержаться текст запроса или подсказка, позволяющая пользователю ввести данные определенного типа. Функции этого типа приостанавливают выполнение программы до осуществления ввода данных с клавиатуры или при помощи устройства указания. При этом в ответ на запрос функций семейства GETxxx нельзя вводить выражения АВТОЛИСПа. Механизм использования этих функций сходен, разницу составляет лишь тип данных, принимаемых каждой функцией. Рассмотрим некоторые из них: (getint [<запрос>]) Эта функция приостанавливает вычисления для ввода целого числа и возвращает это целое число. Необязательный аргумент <запрос>
21
представляет собой строку, отображаемую на экране в виде приглашения на ввод. Например: (setq число (getint)) Здесь функция (GETINT) используется без аргументов, поэтому на командной строке не появляется никакого запроса-подсказки. (setq число (getint "Введите масштаб:")) Здесь в качестве аргумента используется запрос "Введите масштаб:", поэтому в командной строке появляется запрос "Введите масштаб:" и вычисления приостанавливаются до завершения ввода. В ответ на запрос функции GETINT нельзя вводить выражение АВТОЛИСПАа. Смотрите также описание функции INITGET. (getreal [<запрос>]) Эта функция приостанавливает вычисления для ввода вещественного числа и возвращает это число. Необязательный аргумент <запрос> представляет собой отображаемую на экране строку. Примеры: (setq число (getreal)) (setq число (getreal "Масштабный коэффициент:")) В ответ на запрос функции GETREAL нельзя вводить выражение АВТОЛИСПа. Смотрите также описание функции INITGET. (getkword [<вопрос>]) Функция GETKWORD запрашивает ключевое слово. Список допустимых ключевых слов определяется заранее с помощью функции INITGET. Функция GETKWORD возвращает строку, соответствующую введенному пользователем ключевому слову. При вводе недопустимого ключевого слова АВТОКАД вновь запрашивает ввод. В ответ на нулевой ввод (если он допустим) возвращается нуль. Нуль возвращается и в том случае, если не обнаружена строка, соответствующая заданному ключевому слову. Например, последовательность вызовов: (initget 1 "Да" "Нет") (setq x (getkword "Вы уверены? (Да или Нет) ")) выдает пользователю подсказку "Вы уверены? (Да или Нет)" и присваивает переменной X значение "Да" или "Нет" в зависимости от ответа пользователя. Если ответ не совпадает ни с одним из ключевых слов или является нулевым, АВТОКАД вновь запросит ввод.
22 В ответ на запрос выражения АВТОЛИСПа.
функции
GETKWORD
нельзя
вводить
initget [<разряд>] [<строка>]) Эта функция определяет варианты применения GET-функций, кроме функций GETSTRING и GETVAR. Функция INITGET всегда возвращает нуль. Необязательный аргумент <разряд> представляет собой целое число с одним из следующих значений: <разряд> 1 2 4 8 16 32
Смысл Запрет пустого отклика Запрет нулевых значений Запрет отрицательных значений Отказ от контроля пределов, чертежа Возвращение трехмерной, а не двухмерной точки Использование штриховых линий при изображении резиновой нити
Эти значения можно складывать в любом сочетании, формируя число в диапазоне от 0 до 63. Если при пользовательском вводе не выполняются какие-либо из специфицированных условий (например, вводится нуль при наличии запрета на ввод нулевых значений), АВТОКАД выводит на экран соответствующее сообщение и повторяет запрос на ввод. Например, последовательность вызовов: (initget (+ 1 2 4)) (setq возраст (getint "Сколько Вам лет?")) запрашивает возраст пользователя, автоматически повторяя запрос, если пользователь вводит нулевое или отрицательное значение. Отсутствию аргумента <разряд> соответствует нулевое значение (нет условий). Значения этого аргумента обрабатываются только теми GETфункциями, для которых они имеют смысл, как показано в следующей таблице: GET-функция Управляющие разряды функции INITGET "getint" "getreal"
1, 2, 4 1, 2, 4
23
"getdist" "getangle" "getorient" "getpoint" "getcorner" "getkword" "getorient" "getorient"
1, 1, 1, 1, 1, 1 ---
2, 2, 2, 8, 8,
4, 32 32 32 16, 32 16, 32
Организация вывода информации в интерактивных процедурах АВТОЛИСП содержит несколько функций, предназначенных для выполнения вывода данных. Они позволяют выводить информацию на экран для организации диалога с пользователем. (prompt <сообщение>) Эта функция выводит на экран сообщение в поле подсказок системы АВТОКАД и возвращает NIL. <Сообщение> здесь - это строка литер, заключенная в кавычки. Например, если в каком либо месте программы понадобилось напечатать "Попытайтесь еше раз", то в программу можно ввести следующаю строку: (prompt "Попытайтесь еше раз") Функция TERPRI печатает пустую строку в поле подсказок системы АВТОКАД и возвращает NIL. Она имеет формат: (terpri) Ее используют для того, чтобы в программе запросы функций АВТОЛИСПа выводились с новой строки. Вместо этой функции часто используют управляющий символ "\n" непосредственно внутри запроса или сообщения: (prompt "\n Программа выполнена") ЛАБОРАТОРНАЯ РАБОТА N3
ПРОГРАММИРОВАНИЕ ПЕРЕХОДОВ ПО УСЛОВИЯМ И ЦИКЛОВ НА ЯЗЫКЕ АВТОЛИСП. ИЗУЧЕНИЕ РАСШИРЕННЫХ СРЕДСТВ РАБОТЫ СО СПИСКАМИ 1. Подготовка к работе
24 Изучить по лекциям и методической разработке вопросы связанные с лексикой, особенностями представления данных, выражений на АВТОЛИСПе. Изучить основные математические функции АВТОЛИСПА. Изучить функцию DEFUN и основные функции ввода -вывода для организации диалога с пользователем. Изучить функции организации переходов по условиям, организации циклов и функции работы со списками. 2. Контрольные вопросы 1. Создание пользовательских функций , формат функции DEFUN. 2. Списки, их создание и работа с ними. 3. Элементарные селекторы и конструкторы АВТОЛИСПа. 4. Функции отношения и сравнения в АВТОЛИСПе. 5. Организация переходов по условию в АВТОЛИСПе. 6. Использование функции IF, PROGN для организации переходов по условиям. 7. Использование функции COND для организации переходов по условиям. 8. Организация циклов в АВТОЛИСПе. Функции REPEAT, WHILE. 9. Расширенные средства работы со списками. 10. Функции APPLY, MAPCAR. 11. LAMBDA функция и ее использование при создании пользовательских функций. 3.Задание на выполнение работы 1. Загрузить АВТОКАД и выйти в его графический редактор, обеспечив при этом работу АВТОЛИСПУ. Войти в текстовый редактор АВТОКАДА для создания или редактирования разрабатываемых программ. 2. Используя функции переходов по условиям создать функцию LEN4, которая вычисляет длину списка Х, содержащего 0...4 элемента. Убедитесь в правильности работы созданной функции. 3. Используя функции переходов по условиям создать функцию SUM4, производящую суммирование элементов списка А, состоящего из 0...4 действительных чисел. Убедитесь в правильности работы созданной функции.
25
4.Создать список S1 из элементов а, b, (c + D), 12,5, 0,08 и список S2 из элементов (ab), -10,5, "dog", "time" и образовать из них новый список S. 5.С помощью функций переходов по условиям, циклов и функции CONS создать функцию LISTY, которая формирует список SC из 10 четных чисел, если введенное число четное и список SN из 10 нечетных чисел, если введенное число нечетное. Числа в списках SC и SN расположить в порядке убывания. 6.С помощью функции MAPCAR создать функцию F1, производящую умножение каждого элемента созданного списка SN на первый элемент этого списка. 7.Обратить списки SC и SN. 8.Извлечь последние элементы из списков SN и SC и определить их длину. 9.С помощью функции MAPCAR произвести умножение каждого элемента списка SN на 3 и деление каждого элемента списка SC на 2. 10.При создании функций использовать диалог в виде запросов и подсказок, созданный функциями семейства GET и INITGET. 11. Выйти из АВТОКАДа командой END. 12. Составить отчет, который должен содержать все вводимые функции АВТОЛИСПА и возвращаемые результаты по всем пунктам задания. 4.Общие сведения Организация переходов по условию АВТОЛИСП дает возможность создавать конструкции, подобные условным переходам в языках программирования высокого уровня. В языке имеется две функции, реализующие такие конструкции - IF и COND. Для задания самих условий в этих случаях используются функции сравнения и логические функции. Функция IF Эта функция позволяет задать выполнение какой-либо операции в случае выполнения заданного условия. Кроме того имеется возможность задания альтернативной операции в случае, если условие не выполняется. Формат этой функции: (if <тест-выражение> <выражение-тогда> [<выражение-иначе>]) При выполнении функции осуществляется проверка истинности <тест-выражения>. Если оно истинно, то выполняется <выражение-тогда> и возвращается результат этого выполнения, в противном случае
26 выполняется необязательное <выражение-иначе> и возвращается его результат. Если результат <тест-выражения> NIL и отсутствует <выражение-иначе>, то возвращается NIL. Например: (if (= 1 3) "Да!!" "Нет") возвращает "Нет" (if (= 2 (+ 1 1)) "Да!!") возвращает "Да!!" (if (= 2 (+ 3 4)) "Да!!") возвращает nil Если по результатам тестирования нужно выполнить не одно, а несколько выражений, то используют функцию PROGN (progn <выражение1><выражение2>...) Эта функция вычисляет одно <выражение> за другим, возвращая значение последнего из них. Функция PROGN может быть использована для вычисления нескольких выражений там, где обычно вычисляется только одно. Например: (if (= a b) (progn) (setq a (+ a 10)) (setq b (- b 10)) ) ) Функция IF обычно вычисляет одно выражение типа "then". В этом примере использование функции PROGN обеспечивает возможность вычисления не одного, а двух выражений. Функция COND в отличии от функции IF позволяет построить конструкцию,в которой можно проверять не одно, а несколько условий: (cond (<условие1> <результат1><условие2><результат2>...)...) Работает она так: вычисляется <условие1>. Если оно выполняется, то выполняются действия, следующие за этим условием <результат1>. Затем управление передается функциям, следующим за функцией COND. Если же <условие1> не выполняется, то выражения, следующие за ним также не выполняются, а проверяется <условие2> и т.д. При этом, в отличие от функции IF, за каждым условием может следовать любое количество выражений <результат>, которые нет необходимости объединять с помощью функции PROGN. Если ни одно из условий не выполняется, то работа функции COND а этом заканчивается. Функция COND является основной функцией языка АВТОЛИСП, используемой для проверки условий. Например, следующая функция COND используется для вычисления абсолютной величины:
27
(cond ((minusp a) (-a)) (t a) Если переменной "а" присвоено значение -10, функция возвращает значение 10. Функция COND может быть использована как функция выбора. Чаще всего в качестве последнего выражения типа <условие> используется константа "Т". Рассмотрим еще один простой пример. Функция проверяет ввод пользовательской строки, обозначенной символом "s", и возвращает 1, если эта строка равна "Y" или "y" и 0, если она равна "N" или "n", и "nil" в любом другом случае. (cond ((= s "Y") 1) ((= s "y") 1) ((= s "N") 0) ((= s "n") 0) (t nil) ) Организация циклов в АВТОЛИСПЕ АВТОЛИСП имеет средства организации повторных выполнений некоторого набора действий определенное количество раз или до выполнения некоторого условия. Простейшей функцией, организующей цикл, является функция REPEAT: (repeat <число> <выражение1><выражение2>...) В качестве аргумента <число> этой функции может быть задано любое целое положительное число. Функция вычисляет последовательность <выражение> столько раз, сколько задано аргументом <число> и возвращает значение последнего <выражения>. Если дано: (setq a 10) (setq b 100) , то вызов (repeat 4 (setq a (+ a 10)) (setq b (+ b 10)) ) возвращает 140. Функция WHILE отличается от функции REPEAT тем, что число повторов в ней не задается, а задается условие выхода из цикла: (while <условие> <выражение1><выражение2>...) Эта функция проверяет <условие> и, если оно выполняется, вычисляет последовательность <выражение>; затем вновь проверяет <условие>. Это продолжается до тех пор, пока <условие> перестанет
28 выполняться; тогда цикл закончится, и функция WHILE возвратит самое последнее значение последнего <выражения>. Если дано: (setq a 1) , то цикл (while (<= a 10) (моя-функция а) (setq a (1+ a)) ) десять раз вызовет пользовательскую функцию "моя-функция", последовательно присваивая переменной А значения от 1 до 10. Затем функция WHILE возвратит число 11. Расширенные средства работы со списками Список - это группа элементов любого допустимого в АВТОЛИСПе типа,заключенная в круглые скобки. АВТОЛИСП как язык функционального программирования имеет широкие возможности работы со списками. Простейшие из них были рассмотрены ранее. Ниже рассматриваются функции, дающие дополнительные возможности при обработке списков. (append <список1><список2>...) Эта функция воспринимает любое количество <списков> и объединяет их в один общий список. Примеры: (append '(a b) '(c d)) возвращает (A B C D) (append '((a) (b)) '((c) (d)) возвращает ((A) (B) (C) (D)) Аргументами функции APPEND должны быть списки. (cons <новый головной элемент> <список>) Эта функция является основным средством формирования списков. Она возвращает второй аргумент, <список>, дополненный первым аргументом (<новый головной элемент>). Например: (cons 'a '(bcd)) возвращает (A B C D) (cons '(a) '(b c d)) возвращает ((A) B C D) Заметим, что головной элемент может быть атомом или списком. Кроме того, функция CONS может воспринимать в качестве второго аргумента не список, а атом, формируя структуру, известную как "пара с точкой". При отображении пары с точкой на экране АВТОЛИСП печатает точку между элементами пары. Пары с точкой занимают в памяти
29
меньше места, чем обычные списки; для доступа ко второму элементу пары можно использовать функцию CDR, например: (cons 'a 'b) (car (cons 'a 'b)) (cdr (cons 'a 'b))
возвращает возвращает возвращает
(A . B) A B
(apply <функция> <список>) Функция APPLY выполняет с аргументами, заданными <списком>, действия, заданные <функцией>.Примеры: (apply '+ '(1 2 3))
возвращает
6
(apply 'strcat '("a" "b" "c")) возвращает "abc" . Функция APPLY работает и с встроенными функциями, и с функциями, определяемыми пользователем (с помощью функций DEFUN или LAMBDA). (foreach <имя> <список> <выражение>) Эта функция присваивает аргументу <имя> поочередно значение каждого элемента аргумента <список>, вычисляя затем аргумент <выражение> для каждого элемента списка. Количество аргументов <выражение> не ограничивается. Функция FOREACH возвращает результат вычисления последнего выражения. Например, вызов: (foreach n '(a b c) (print n)) равносилен последовательности вызовов: (print a) (print b) (print c) если не считать того, что функция FOREACH возвращает результат вычисления только последнего выражения. (mapcar <функция> <список1>...<списокN>) Функция MAPCAR возвращает результат исполнения <функции> с отдельными элементами списков от <списка1> до <спискаN>, задаваемыми как аргументы <функции>. Количество списков должно совпадать с числом аргументов <функции>. Примеры:
30 (mapcar '1+ '(10 20 30))
возвращает (11 21 31)
Это равносильно: (1+ 10) (1+ 20) (1+ 30) если не считать того, что функция MAPCAR возвращает список. Точно так же: (mapcar '1+ '(10 20 30) '(4 3 2))
возвращает (14 23 32)
Это равносильно: (+ 10 4) (+ 20 3) (+ 30 2) (lambda <аргументы> <выражение> ...). Функция LAMBDA обычно применяется тогда, когда нужно иметь дополнительную функцию, используемую только один раз. В этом случае функции дают имя LAMBDA (при этом DEFUN не требуется). Здесь <аргументы> - это список аргументов функции (аналогично DEFUN); <выражение > - это операторы функции. Функция LAMBDA возвращает функцию, имеющую заданные <аргументы>, выполняющую заданные <выражения> и не имеющую имени. Функцию LAMBDA можно использовать самостоятельно. Например: (lambda (a b c) (* a (- b c ))) 56 47 12) возвращается 1960. Обычно необходимости в таком использовании нет. Однако имеет смысл ее использовать с функциями APPLY и MAPACAR, которые выполняют действия над списками аргументов. Это полезно в тех случаях, когда некоторые из аргументов функции являются константами или задаются каким-либо другим способом. Например: (mapcar '(lambda (x) (+ x 3)) '(10 20 30)) возвращает (13 23 33) (mapcar '(lambda (x y z) (* x (- y z) ) '(5 6) '(20 30) '(14 5.0) ) возвращает (30 150.000000) (last <список>) Эта функция возвращает последний элемент <списка>, который не должен быть пустым. Например:
31
(last '(a d c d e)) (last '(a d c (d e)))
возвращает возвращает
E (D E)
Из этих примеров видно, что функция LAST возвращает атом или список. (length <список>) Эта функция возвращает длину <списка>. Например: (length '(a b c d)) (length '(a b (c d))) (length '())
возвращает возвращает возвращает
4 3 0
(member <выражение> <список>) Эта функция отыскивает вхождение аргумента <выражение> в аргумент <список> и возвращает остаток <списка>, начиная с первого вхождения <выражения>. Если искомого вхождения нет, функция возвращает нуль. Например: (member 'c '(a b c d e)) (member 'q '(a b c d e))
возвращает возвращает
(c d e) nil
(nth <список>) Эта функция возвращает -й элемент <списка> (первый элемент считается нулевым). Функция возвращает нуль, если больше длины <списка>. Например: (nth 3 '(a b c d e)) (nth 0 '(a b c d e)) (nth 5 '(a b c d e))
возвращает D возвращает A возвращает nil
(reverse <список>) Функция возвращает список с обратным расположением элементов, например: (reverse '((a) b c))
возвращает
(C B (A))
(subst <новый элемент> <старый элемент> <список>) Эта функция просматривает <список> в поисках <старого элемента> и возвращает копию <списка>, в которой все вхождения <старого элемента> заменены <новым элементом>. Если <старый элемент> не найден, функция возвращает <список> без изменений. Если дано: (setq sample '(a b (c d) b)),
32 то (subst 'qq 'b sample) (subst 'qq 'z sample) (subst 'qq (c d) sample) (subst '(qq rr) '(c d" sample) (subst '(qq rr) 'z sample)
возвращает возвращает возвращает возвращает возвращает
(A QQ (C D) QQ) (A B (C D) B) (A B QQ B) (A B (QQ RR) B) (A B (C D) B)
Указания по работе с текстовым редактором После выхода в графический редактор ввести команду АВТОКАДа :edit. В ответ на появившийся запрос задать имя создаваемого или редактируемого файла с расширением .lsp и выйти в редактор NCEDIT. Справки по работе с этим редактором можно получить используя клавишу F1. После редактирования или создания файла с программой на АВТОЛИСПе сохранить ее с помощью F2 (SHIFT-F2 - переименовать) и выйти из редактора через F10. Оказавшись в графическом редакторе АВТОКАДа загрузить созданную программу функцией (load "имя файла"). Программа загрузится и сразу же начнет исполняться. Возвращается результат работы программы. ЛАБОРАТОРНАЯ РАБОТА N4
СОЗДАНИЕ ФУНКЦИЙ ПОЛЬЗОВАТЕЛЯ С ИСПОЛЬЗОВАНИЕМ РЕКУРСИВНЫХ ОПРЕДЕЛЕНИЙ 1. Подготовка к работе Изучить по лекциям и методической разработке вопросы связанные с лексикой, особенностями представления данных, выражений на АВТОЛИСПе. Изучить основные математические функции АВТОЛИСПА. Изучить функцию DEFUNN и основные функции ввода -вывода для организации диалога с пользователем. Изучить функции организации переходов по условиям, организации циклов и функции работы со списками.
33
Изучить принципы построения функциональных программ с использованием рекурсивных вызовов. Изучить принципы построения схем рекурсивных вызовов на модели. Построить схемы рекурсивных вызовов для всех создаваемых в работе функций. 2. Контрольные вопросы 1. Создание функций пользователя с помощью функции DEFUN. 2. Создание функций пользователя с помощью функции LAMBDA. 3. Создание списков и работа с ними. 4. Расширенные средства обработки списков. 5. Принципы создания функций с использованием рекурсии. 6. Модель рекурсивных вызовов функции. 7. Конструкторы функций и их использование. 8. Использование функции MAPCAR для работы со списками. 9. Использование функции APPLY для работы со списками. 10.Организация циклов в АВТОЛИСПе. 3.Задание на выполнение работы 1. Загрузить АВТОКАД и выйти в его графический редактор, обеспечив при этом работу АВТОЛИСПу. Войти в текстовый редактор АВТОКАДа для создания или редактирования разрабатываемых программ. 2. Вычисление факториала целого числа n производится по формуле: !n = n(n-1)(n-2)...1. Создать функцию FACT ,которая производит вычисление факториала целого числа с использованием рекурсии. 3. Числа Фибоначчи вычисляются следующим образом: F(1) = 1 F(2) = 2 F(n) = F(n-1) + F(N-2). Создать функцию NUMBER, которая, используя рекурсию, производит вычисление этих чисел. 4. Создать функцию MEM, которая отыскивает атом X в списке Y. В случае удачного поиска должна возвратиться часть списка, начинающаяся с 1-го найденного элемента, в противном случае NIL. 5.Создать функцию NO-NEGATIVE, которая производит фильтрацию списка чисел и создание из него нового, который не содержит отрицательных чисел.
34 6. При создании функций использовать рекурсивные вызовы и диалог в виде запросов и подсказок, созданный функциями семейства GET и INITGET. 7. Выйти из АВТОКАДа командой END. 8. Составить отчет, который должен содержать схемы рекурсивных вызовов для всех создаваемых функции и возвращаемые результаты по всем пунктам задания. 4.ОБЩИЕ СВЕДЕНИЯ Рекурсивное программирование. Рекурсивные процедуры занимают важное место почти во всех программах, связанных с исскуственным интеллектом. Многие практические ситуации предполагают рекурсивное или самоповторяющееся поведение , возвращающееся к самому себе. Можно сказать, что рекурсия простая, если вызов функции встречается в некоторой ветви лишь один раз. Простой рекурсии в процедурном программировании соответствует простой цикл. Сложную рекурсию можно объяснить следующим образом: - вычисления начинаются с вызова некоторой функции, которая в свою очередь вызывает функции, входящие в ее определения и т.д. в соответствии с иерархией определений и структурой условных предложений. Функции часто либо прямо, либо косвенно вызывают сами себя. В рекурсивном описании действий имеет смысл обратить внимание на следующие обстоятельства. Во-первых , процедура содержит всегда по крайней мере одну терминальную ветвь и условие окончания. Вовторых, когда процедура доходит до рекурсивной ветви, то функционирующий процесс приостанавливается и новый такой же процес запускается с начала, но уже на новом уровне. Прерванный процесс каким-нибудь образом запоминается. Он будет ждать и начнет исполняться лишь после окончания нового процесса. В свою очередь, новый процесс может приостановиться, ожидать и т.д. Таким образом, образуется как бы стек прерванных процессов, из которых выполняется лишь последний в настоящий момент времени процесс; после окончания его работы продолжает выполняться предшествующий ему прцесс. Целиком весь процесс выполнен , когда стек снова опустеет, или, другими словами, все прерванные процессы выполнятся. Рекурсию можно использовать для определения как предикатов , так и функций. Рассмотрим пример простой рекурсии.
35
(defun MEMB (a l) ; имя функции и список аргументов (cond ((null l) nil) ; список l пуст ? ((eq l (car l) a) l) ;элемент а найден ? (t (MEMB a (cdr l))))) ; элемент а - в хвосте списка l? С помощью этой функции можно проверить , принадлежит ли некоторый элемент A данному списку L или нет. Тело функции состоит из условного предложения , содержащего три ветви. Они участвуют в процессе вычислений в зависимости от возникающей ситуации: 1. ((null l) nil) : Аргумент - пустой список либо с самого начала , либо потому , что просмотр списка окончен. 2. ((eq l (car l) a) l) : Первым элементом является искомый элемент. В качестве результата возвращается список , в котором А - первый элемент. 3. (t (MEMB a (cdr l))) : Ни одно из предыдущих утверждений не верно: в таком случае либо элемент содержится в хвосте списка , либо вовсе не входит в список. Если список L пуст либо А в него не входит , то функция возвращает NIL. В противном случае она возвращает в качестве своего значения ту часть списка , в которой искомое А является его первым элементом. Это отличное от NIL выражение соответствует логическому значению "истина". Пример вызова функции и получение результатов: (MEMB 'b '(a b c d)) После ввода этого выражения интерпретатор выдаст результат (B C D) В определении предиката MEMB первоначальная задача разбита на три подзадачи. Первые две из них сводятся к просым условиям окончания. Третья решает такую же задачу , но на шаг более короткую.
36 Ее решение можно рекурсивно свести к функции , решающей первоначальную задачу. Пронаблюдав с помощью трассировки за вычислением функции MEMB можно понять принцип работы программы: (trace MEMB) (MEMB) (MEMB 'c '(a b c d)) MEMB : A=C L = (A B C D) MEMB : A=C L = (B C D) MEMB : A=C L = (C D) MEMB = (C D) MEMB = (C D) MEMB = (C D) (C D)
; включение трассировки ; загрука функции ; вызов функции ; вызов уровня 1 ; вызов уровня 2 ; вызов уровня 3 ; значение уровня 3 ; значение уровня 2 ; значение уровня 1 ; значение формы
На первых двух уровнях рекурсии вычисления осуществляются по третьей, рекурсивной ветви. В рекурсивном вызове первым аргументом является С, так как искомый элемент на каждом шаге один и тот же. Вторым аргументом берется хвост списка текущего уровня (CDR L). На третьем уровне значением предиката (EQ L (CAR L) A) становится Т, поэтому на этом уровне значением всего вызова станет значение соответствующего результирующего выражение L=(C D). Это значение возвращается на предыдущий уровень, где оно будет значением вызова MEMB в рекурсивной ветви и, таким образом, станет значением всего вызова на втором уровне. Потом это значение возвращается далее на уровень и, в конце концов, выводится пользователю. В процессе спуска по ходу рекурсии на более низкие уровни значение параметра А не меняется , в то время как значения параметра L меняется при переходе на следующии уровень. Значения прдыдущего уровня сохраняются, поскольку связи переменных ассоциируются с уровнем. Значение предыдущих уровней скрыты до тех пор, пока на них не вернется управление, после этого старые связи вновь становятся активными. В приведенном примере после возврата на предыдущие уровни эти связи не используются.
37
Сообщения об ошибках Здесь приводится список сообщений, которые вы можете увидеть на своих экранах при формировании и отладке функций Автолиспа. Если не определена пользовательская функция *ERROR* (*ERROR* имеет нулевое значение), то выводятся стандартные сообщения об ошибках в форме: error: сообщение которое выводится вслед за обратной трассировкой функции, при исполнении которой произошла ошибка. Если определена пользовательская функция *ERROR*, то она вызывается со своим единственным аргументом -- сообщением об ошибке. AutoCAD rejected function //отказ исполнить функцию// Неправильно заданы аргументы функции (например, задана несуществующая переменная для функции "getvar", или для функции "setvar" задана переменная, защищенная от записи), или неверно употребляется сама функция в текущем контексте. Например, "get"функцию нельзя использовать внутри функции "coommand". bad argument type //недопустимый тип аргумента// Функции задается неправильный тип аргумента (например, функции "strlen" задается целочисленный аргумент). bad association list //неправильный фссоциативный список// Список, задаваемый для функции "assoc", не содержит ключей. bad entmod list //недопустимый список для функции "entmod"// Список объектной информации для функции "entmode" задан в недопустимой форме (не в той, в какой он возвращается функцией "entget"). bad formal argument list //недопустимый список формальных аргументов// При вычислении функции Автолисп бракует список формальных аргументов. Вероятно, это и не функция, а обычный список. bad function //недопустимая функция// Первый элемент списка не является допустимым именем функции. Вероятно, это идентификатор переменной или чмсло. Данное
38 сообщение может также указывать на неправильное определение функции -- не забывайте о списке формальных аргументов. bad list //неправильный список// Функции задан неправильный список. Данное сообщение может появиться, если вещественный элемент списка начинается с точки; в этом случае нужно вставить лидирующий нуль. Bad node. //неправильный узел// Функцией обнаружен элемент недопустимого типа. bad node type in list //неправильный тип узла// Функцией "foreach" обнаружен элемент недопустимого типа. bad point argument //недопустимый точечный аргумент// Неправильно определена точка (список из двух вещественных чисел), задаваемая функции в качестве аргумента. Следите за тем, чтобы вещественное число не начиналось с десятичной точки; в этих случаях следует использовать лидирующий нуль. bad point value //недопустимое значение точечного объекта// То же, что и в предыдущем случае. boole arg1 < 0 or > 15 //первый аргумент функции "boole" меньше 0 или больше 15// Первый аргумент функции "boole" должен быть целым числом в диапазоне от 0 до 15. can't evaluate expression //невозможно вычислить выражение// Эта ошибка может быть вызвана неправильным употреблением десятичной точки или другими погрешностями при формировании выражения. console break //прерывание с консоли// Пользовательский ввод CTRL C при исполнении функции. divide by zero //деление на нуль// Деление на нуль недопустимо. extra right paren //лишняя правая скобка// Обнаружены лишние правые скобки. file not open //файл не открыт// Для операции ввода/вывода задан дескриптор неоткрытого файла.
39
Function cancelled //отбой функции// Ввод CTRL C в ответ на запрос. function undefined for argument //недопустимое значение аргумента// Аргумент, заданный для функции "log" или "sqrt", находится вне допустимого диапазона. function undefined for real //недопустимое употребление вещественного аргумента// Вещественный аргумент задан там, где нужно задавать целочисленный, например, (lsh val 1.2). improper argument //неправильный аргумент// Для функции "gcd" задан отрицательный или нулевой аргумент. incorrect number of arguments to a function //неправильное количество аргументов// Количество аргументов пользовательской функции не совпадает с количеством формальных аргументов, специфицированных в функции "defun". insufficient node space //недостаток памяти для узлов// Не хватает динамической области памяти для выполнения заданных операций. insufficient string space //недостаток памяти для строк// Не хватает динамической области памяти для размещения текстовой строки; invalid argument //неправильный аогумент// Неправильный тип аргумента, или значение аргумента вышло за допустимые границы. invalid character //неверный символ// Выражение содержит неправильный символ. invalid dotted pair //неправильная пара с точкой// Пара с точкой представляет собой список из двух элементов, разделенных конструкцией "пробел-точкапробел". Данная ошибка появляется, если вы начинаете вещественное чмсло с десятичной точки; в таких случаях нужно употреблять лидирующий нуль. LISPSTACK overflow //переполнение стека//
40 Превышен объем памяти, выделенный под стек Автолиспа. Эта ситуация может быть вызвана чрезмерной рекурсией или слишком большим списком аргументов функции. Попытайтесь увеличить значение контекстной переменной LISPSTACK. misplaced dot //неправильное положение точки// Эта ситуация возникает, если вещественное число начинается с десятичной точки; это число должно начинаться с нуля. null function //нулевая функция// Попытка вычислить функцию, имеющую нулевое значение. quit/exit abort //вызов функции "quit" или "exit"// Результат вызова функции "quit" или "exit"; эти функции в настоящее время не используются в Автолиспе. too few arguments //слишком мало аргументов// Слишком мало аргументов задано для встроенной функции. too many arguments //слишком много аргументов// Слишком много аргументов задано для встроенной функции. unexpected signal nnn //непредусмотренный сигнал// (Только для UNIX-систем). Непредусмотренный операционной системы.
сигнал