Полезное:
Как сделать разговор полезным и приятным
Как сделать объемную звезду своими руками
Как сделать то, что делать не хочется?
Как сделать погремушку
Как сделать так чтобы женщины сами знакомились с вами
Как сделать идею коммерческой
Как сделать хорошую растяжку ног?
Как сделать наш разум здоровым?
Как сделать, чтобы люди обманывали меньше
Вопрос 4. Как сделать так, чтобы вас уважали и ценили?
Как сделать лучше себе и другим людям
Как сделать свидание интересным?
Категории:
АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника
|
Управляющие конструкции Автолиспа - ветвление
Поскольку список - главное действующее лицо языка Лисп, следует тщательно рассмотреть набор функций по работе с ними. До некоторой степени список аналогичен массиву в языках типа Паскаля. Там доступ к конкретному элементу списка решается просто - указывается его номер: a[5]. В Лиспе все несколько сложнее. Функция (CAR l) возвращает первый элемент списка l. Например, (CAR (LIST 10 20)) вернет 10. Если список l является описанием координат точки, то (CAR l) возвращает координату X. Функция (CADR l) возвращает все элементы списка l, кроме первого. Иначе говоря, у списка отрывается "голова", а возвращается остающийся "хвост", причем даже если этот "хвост" длиной в один атом, он все равно будет списком: (CDR (LIST 10 20)) возвращает (20) Функция CDR не годится для получения координаты Y точки - она возвращает список, а координата, конечно же, должна быть выражена атомом - вещественным числом. По-хорошему надо из списка, возвращаемого функцией CDR, выделить первый элемент, написав (SETQ p (LIST 10 20)); координаты точки p (SETQ y (CAR (CDR p))) Но такая запись выглядит весьма громоздко. Поэтому в Лиспе предусмотрена возможность использования вложенных функций CAR и CDR, которые будут называться соответственно CADR, CDAR, CAAR, CDDR и так далее (до четырех уровней вложенности). При этом (CADR l) эквивалента (CAR (CDR l)). Последний элемент списка как атом возвращает функция (LAST l). В принципе ее можно использовать для получения координаты Y, но где гарантия, что в один прекрасный день пользователь не включит режим использования трехмерных точек? Тогда LAST станет возвращать уже координату Z и ваша программа тут же потеряет работоспособность. И, наконец, самая общая функция выделения элементов из списка: (NTH n l), которая возвращает n-й элемент списка l. Нумерация элементов списка в функции NTH начинается с нуля! Итак, поскольку наиболее часто нам нужно выделить отдельные координаты точки, подытожим, как это легче всего сделать:
Таблица - Получение координат точек.
Разбор точек на координаты используется, если необходимо рассчитать положение точки через приращения. Например, при отрисовке фаски нужно узнать координаты точки P2, зная точку P1:
Рисунок Отрисовка фаски. Хотя угол здесь задан в явном виде, использование функции POLAR будет некорректным: мы не знаем расстояние P1P2. Если его высчитывать как гипотенузу прямоугольного треугольника, точность вычисления квадратного корня окажется ограниченной и мы не попадем в точку P2. Если бы мы рисовали фаску вручную, то мы бы ввели приращения по осям в виде @3,3 (т.е. переместиться от точки P1 вправо на 3мм и верх на 3 мм). Сделаем то же самое в Автолиспе: (SETQ p2 (LIST (+ (CAR p1) 3) (+ (CADR p1) 3))) Такая запись является стандартным способом расчета координат точек в приращениях. При использовании списков, особенно списков-данных, часто необходимо добавлять в имеющийся список новые и новые значения, как бы "приклеивая" их к его хвосту. Для этого предназначена функция (APPEND l1 l2), которая добавляет в конец списка l1 список l2 и возвращает новый, удлиненный список. Список l1 от этого автоматически не меняется, нужно сохранять результат выполнения функции APPEND. Обратите внимание: для добавления в список атома его сначала нужно превратить список из одного элемента! Пример: в переменной а хранится список вида (19 49). К нему нужно добавить число 20. Делается это так: (SETQ a (APPEND a (LIST 20))) Вся эта работа со списками нужна нам не сама по себе, а для решения той или иной задачи. А любая мало-мальски сложная задача, в свою очередь, требует для своего решения применения ветвлений и циклов. Поэтому сейчас мы начнем рассматривать управляющие конструкции Автолиспа - ветвления и циклы. И ветвление, и цикл в обязательном порядке содержат проверку условия. В качестве условий в Лиспе используются логические функции, возвращающие T (true - истина) или NIL (ложь): "<", ">", "<=", ">=", "=", "/=". Обратите внимание: операция "не равно" записывается не так, как в большинстве других языков программирования! Функции сравнения могут применяться к целым и вещественным числам, а также текстовым строкам, но не к спискам. Примеры: (= 2 2) возвращает T (= 2 5) возвращает NIL (= "ABC" "AB") возвращает NIL Если мы сравниваем вещественные числа, то следует помнить об ограниченной точности вычислений с ними. Особенно это относится к тригонометрическим функциям. Поэтому крайне нежелательно сравнивать результат тригонометрической функции с константой, иначе возникают трудноуловимые казусы следующего вида: (SETQ a1 (SIN 0.0)) (SETQ a2 (SIN (* 2.0 PI))) Тогда (= a1 a2) возвращает NIL, т.е. с точки зрения Лиспа , поскольку не равен точно нулю. Что же делать, если нужно сравнить два вещественных числа, когда хотя бы одно из них - результат вычисления тригонометрической или иной функции? (заметим, что аналогичная проблема в других языках программирования просто обходится молчанием). Создатели Лиспа ввели в язык специальную функцию сравнения с заданной точностью: (EQUAL e1 e2 точность) Здесь точность - число (0.1, 0.01..), указывающее, сколько знаков поле запятой принимается во внимание при сравнении выражений e1 и e2. Поэтому функция (EQUAL (SIN 0)(SIN (* PI 2)) 0.1) вернет T. Функции сравнения могут объединяться при помощи логических функций, образуя сложные условия. В Лиспе имеется богатый набор логических функций (заметно больший, чем в других языках), из которых реально достаточно знать следующие четыре:
Таблица - Логические функции языка Автолисп.
Теперь мы готовы к рассмотрению функции IF, обеспечивающей ветвление в программе. Ее общий вид: (IF c f1 [f2] )
Здесь с - условие (простое или сложное):, f1 - функция, выполняемая, если условие истинно (часть "то"), а f2 - функция, выполняемая, когда условие ложно (часть "иначе"), причем квадратные скобки говорят о том, что часть "иначе" может отсутствовать. _&_ Простейший пример:
(IF (< a 0) (PROMPT "\nПеременная a меньше нуля") (PROMPT "\n"Переменная a больше или рана нулю")) А как быть, если нужно в случае выполнения (или невыполнения) условия выполнить не одну, а сразу несколько функций? Ведь синтаксис функции IF разрешает записать только одну. Проблема решается так же, как в языке Паскаль: там используются операторные скобки begin..end, а в Лиспе - функция (PROGN f1 f2.. fn). Она всего лишь объединяет функции f1 f2.. fn в один блок, который можно подставить в функцию IF. Например, мы решаем квадратное уравнение и в переменную d записали дискриминант. Теперь нужно посчитать действительные корни и вывести их на экран: (IF (>= d 0) (PROGN (SETQ x1 (/ (+ (* b -1) (SQRT d)) (* 2 a)) (SETQ x2 (/ (- (* b -1) (SQRT d)) (* 2 a)) (PROMPT "\nX1=") (PRINT x1) (PROMPT "\nX2=") (PRINT x2) ); конец PROGN (PROMPT "\nДействительных корней нет"); "иначе" ) Продолжая рассматривать параллели с Паскалем, обратимся к функции COND, обеспечивающей множественное ветвление аналогично паскалевскому оператору CASE. Ее общий вид: (COND (c1 f11 f12... f1n1) (c2 f21 f22... f2n1) ... (cm fm1 fm2... fmnm) ) Здесь с1..cm - логические условия, fnm - функции, выполняемые при выполнении того или иного условия. Основное назначение функции COND - обработка ввода пользователя, например, так:
(SETQ a (GETINT "\n1 - фаска, 2 - галтель, 3 - выточка")) (COND ((= a 1)....); фаска ((= a 2)....); галтель ((= a 3)....); выточка )
|