Главная Случайная страница


Полезное:

Как сделать разговор полезным и приятным Как сделать объемную звезду своими руками Как сделать то, что делать не хочется? Как сделать погремушку Как сделать так чтобы женщины сами знакомились с вами Как сделать идею коммерческой Как сделать хорошую растяжку ног? Как сделать наш разум здоровым? Как сделать, чтобы люди обманывали меньше Вопрос 4. Как сделать так, чтобы вас уважали и ценили? Как сделать лучше себе и другим людям Как сделать свидание интересным?


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






Управляющие конструкции Автолиспа. Циклы





 

Циклы в Лиспе обеспечиваются функциями. Простейшая из них - функция REPEAT вида

(REPEAT n f1 f2... fm)

Здесь n - число повторений, а f1..fm - те функции, которые будут выполняться n раз.

В цикле REPEAT, в отличие от, например, цикла FOR..TO в Паскале, нет переменной, значение которой изменяется от 1 до n. Поэтому таким циклом не стоит решать задачи перебора элементов списка. Для этого существуют специальные функции.

Назначение цикла REPEAT - в основном решение задач отрисовки. Например, если деталь имеет повторяющиеся элементы, можно запросить у пользователя их количество, затем вычленить повторяющийся участок и отрисовать его нужное число раз.

Пример: нарисовать деталь, показанную на рисунке. Число отверстий, идущих с заданным шагом, может варьироваться от 1 до 5.

 
 

Рисунок - Деталь, для отрисовки которой нужен цикл.

 

Предположим, что все данные, кроме числа отверстий, введены, сам контур детали нарисован и левый нижний угол находится в точке с координатами (0,0). Делаем следующее:

...

(INITGET 7)

(SETQ n (GETINT "\nВведите число отверстий:") x (LIST s (/ h 2.0)))

(REPEAT n

(COMMAND "КРУГ" x (/ D 2.0))

(SETQ x (POLAR x 0 m))

)

В этом примере в переменную x записывается текущая координата центра окружности.

 
 

Однако одного такого цикла нам явно недостаточно. Как быть, если мы не знаем заранее, сколько раз нам нужно выполнять то или иное действие? Мы просто знаем, что нужно остановиться при выполнении определенного условия. Например, пусть в той же детали (рисунок 5.1) сверлятся отверстия, причем центр первого из них отстоит от левого края на величину S, а край последнего должен отстоять от правого края на величину B (рисунок 6.2).

Рисунок - Использование цикла "пока".

Конечно, можно рассчитать число отверстий. А можно просто рисовать их до тех пор, пока соблюдается условие:

 

 

где x - текущая координата центра отверстия;

xR - координата правой границы детали.

 

В Лиспе цикл по условию задается функцией WHILE:

(WHILE c

f1 f2... fm)

Здесь c - логическое условие. Цикл выполняется, пока это условие истинно.

В нашем случае (p0 - координаты левого нижнего угла детали):

;координата х правого конца детали

(SETQ pr (+ (CAR p0) L))

; Координата центра первого отверстия

(SETQ x (+ (CAR p0) S))

(WHILE (< (- xr (+ x (/ D 2))) B)

(COMMAND "CIRCLE"

(LIST x (+ (CADR p0) H)) D)

(SETQ x (+ x m))

)

Обратите внимание: при использовании цикла "пока" нужно позаботиться о задании начальных условий (в рассматриваемом примере - о присваивании переменной х координаты первого отверстия), поскольку условие цикла проверяется ДО входа в него и, если оно не соблюдается, цикл "пока" не выполняется ни разу.

В Лиспе нет цикла с переменной, которая меняется от min до max с заданным шагом. Между тем такие циклы есть практически во всех других языках программирования. В чем же дело? В том, что список - особая структура данных. Наиболее часто цикл с переменной нужен для прохода по всем элементам массива и их обработки (например, суммирования для нахождения среднего). В Лиспе для обработки каждого элемента списка предусмотрены два особых цикла: FOREACH и MAPCAR.

Нет необходимости искусственно (при помощи цикла WHILE) создавать цикл с переменной для прохода по списку!

Рассмотрим цикл FOREACH:

(FOREACH name list exp)

Здесь name - имя переменной, в которую последовательно записываются элементы списка list, а exp - выражение Лиспа, выполняемое столько раз, сколько элементов есть в списке list.

Рассмотрим работу цикла на примере. Пусть нам нужно просуммировать все элементы списка data и записать сумму в переменную s. Делается это так:

; Обнуление суммы

(SETQ s 0)

(FOREACH cur data (SETQ s (+ s cur)))

При выполнении этого фрагмента происходит следующее: берется список data, по очереди каждый его элемент, начиная с первого, записывается в переменную cur, после чего выполняется выражение

(SETQ s (+ s cur))

Функция FOREACH имеет одним из своих параметров не число или строку, а выражение Лиспа, поскольку оно является просто списком - еще одна возможность, отсутствующая в большинстве других языков.

В Лиспе нет возможности изменить значение отдельного элемента списка, хотя такая задача возникает довольно часто. Например, при масштабировании изображения нужно все элементы списка размеров size умножить на масштабный коэффициент k.

Существует элегантный способ сделать это при помощи функции MAPCAR. К сожалению, в большинстве книг по Лиспу назначение функции MAPCAR или не разъясняется вовсе, или разъясняется неверно. Ее общий вид:

(MAPCAR 'f l1 l2... ln)

 

MAPCAR выполняет функцию f поочередно над первыми, вторыми, третьими... элементами списков l1.. ln. При этом n должно быть равно числу аргументов функции f, а все списки l1... ln должны содержать одинаковое число элементов. Самое главное - функция возвращает список результатов выполнения функции f.

Перед функцией нужно ставить апостроф, потому что MAPCAR нужна просто ссылка на то место в памяти, где эта функция находится, а не результат выполнения этой функции.

_&_ Рассмотрим работу функции на примере. Итак, предположим, что все элементы списка размеров size нужно умножить на масштабный коэффициент k. Функция умножения требует как минимум два аргумента, в данном случае - текущий элемент списка и коэффициент k.

Первым делом нам придется сформировать вспомогательный список, состоящий из стольких значений k, сколько есть размеров в списке size: ведь функции умножения на вход будут даваться пары значений и для каждого элемента списка size нужно явно указать второй сомножитель. Делается это так:

 

(SETQ coeff NIL)

(REPEAT (LENGTH size)

(SETQ coeff (APPEND coeff (LIST k)))

);REPEAT

 

После этого можно применить функцию MAPCAR:

 

(SETQ size (MAPCAR '* size coeff))

Такое решение работоспособно, но неэлегантно: приходится создавать лишний список coeff. Чтобы этого избежать, можно было бы написать отдельную функцию умножения на коэффициент k. Но снова возникает проблема: как передать в нее значение k?

Для решения подобных казусов было разработано так называемое l-исчисление Черча. Само по себе оно представляет математический аппарат для описания функций. В Лиспе же l-исчисление заключается в наличии возможности создать "одноразовую" функцию, даже не имеющую своего имени. Причем внутри этой функции будут видны все текущие локальные переменные, т.е. для нашего примера снимается вопрос передачи значения k - оно будет видно в такой непоименованной функции, останется только подавать ей на вход по одному значения элементов списка size.

"Одноразовая" функция создается функцией Лиспа LAMBDA:

(LAMBDA (arg1... argn) exp1... expm)

Здесь arg1... argn - список аргументов "одноразовой" функции, а exp1... expm - выражения Лиспа, выполняющие какие-то операции над аргументами.

 

Как и при определении функции при помощи R UN, "одноразовая" функция возвращает результат вычисления последнего выражения, т.е. expm.

Сама по себе функция LAMBDA возвращает создаваемую ей временную функцию. Поэтому ее можно прямо записать как аргумент функции MAPCAR, не забыв поставить апостроф для подавления ее выполнения:

(MAPCAR

'(LAMBDA (x) (* x k))

size

)

Здесь определена функция с одним аргументом x, которая вычисляется для каждого элемента списка size. Полученные произведения "слепливаются" в список, являющийся возвращаемым значением функции MAPCAR.

 

Date: 2015-12-12; view: 508; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.006 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию