Скачиваний:
91
Добавлен:
02.05.2014
Размер:
1.32 Mб
Скачать

( 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 имеет одним из своих параметров не число или строку, а выражение Лиспа, поскольку оно является просто списком - еще одна возможность, отсутствующая в большинстве других языков.

__ Если нужно выполнить сложное действие над элементами списка, есть два пути: написать для этого отдельную функцию и вызвать ее из FOREACH, передавая ей текущий элемент списка как параметр, или объединить несколько выражений при помощи функции PROGN. Например, если нужно и сложить, и перемножить элементы списка, это можно сделать в одном цикле:

; Инициализация суммы и произведения

( SETQ s 0 p 1 )

( FOREACH cur data

( PROGN ( SETQ s ( + s cur ) )

( SETQ P ( * p cur ) )

)

)

В Лиспе нет возможности изменить значение отдельного элемента списка, хотя такая задача возникает довольно часто. Например, при масштабировании изображения нужно все элементы списка размеров 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?

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

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

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

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

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

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

( MAPCAR

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

size

)

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

ЛЕКЦИЯ №7

Основы параметрического проектирования

В соответствии с общей идеологией системы Автокад главное ее предназначение - вовсе не рисование чертежей на компьютере (это приводит к падению производительности труда конструктора в 2..3 раза [2]), а создание на ее основе специализированной САПР определенного класса изделий. Такие САПР резко, в 15..20 раз (результаты внедрения САПР, разработанных на кафедре АСС ТулГУ) повышают производительность.

__ Как же надо правильно использовать Автокад? Анализ работы конструкторско-технологических служб ряда промышленных предприятий позволил установить, что одна из наиболее трудоемких проектных процедур в ходе КТПП - разработка конструкторской документации на ряд близких по конструкции деталей и/или сборочных единиц (ДСЕ), отличающихся в основном своими размерными параметрами или вариантами исполнения. Данная процедура является трудоемким и нетворческим процессом с низкой производительностью и высокой вероятностью внесения ошибок. Особенно часто требуется выпускать конструкторскую документацию на средства технологического оснащения (СТО) машиностроительного производства: тиски, кондукторы, пресс-формы и т.д., причем подготовка этой документации должна вестись опережающими темпами для обеспечения времени на изготовление СТО к моменту запуска изделия в производство.

__ Следует четко определить, какие изделия можно считать подлежащими параметризации. При рассмотрении 2D-проекций детали видно, что они могут быть разбиты на элементарные графические примитивы: отрезки и дуги (рисунок 7.1, а). Каждый примитив однозначно определяется координатами своих базовых точек: начальной и конечной точек отрезка, начальной, конечной точек и центра дуги. Тогда проекцию можно представить в виде графа, вершины которого соответствуют базовым точкам, а ребра - параметрическим связям между ними (рисунок 7.1, б).

Рисунок 7.1 - Проекция детали (а) и ее представление в виде графа (б).

Каждая связь i-j, проходящая от i-й до j-й базовой точки есть вектор параметров

, где (7.1)

- расстояние от точки i до точки j;

- угол между прямой, проходящей через точки i и j и прямой, выбранной в качестве начала отсчета углов.

Введем следующее определение: