Особенности организации памяти в Автолиспе приводят к тому, что следует
ясно различать два понятия: переменная и значение переменной.
Переменная
- указатель на область динамической памяти, имеющий имя.
Значение
переменной - данные, записанные
в динамической памяти начиная с адреса, записанного в переменной.
Изменить можно как переменную, так и ее значение. В первом случае та же
переменная будет указывать на другой участок динамической памяти, а во
втором - в том же участке динамической памяти будет помещено новое значение.
Для присваивания значений переменным в Автолиспе имеются две функции - SET и SETQ.
Функция SETQ (set
by quote)
меняет значение переменной, а не саму переменную. Аргументами функции является
перечень пар "переменная" - "значение". Функция возвращает результат последнего
присваивания.
Например, запись ( SETQ a 10 ) помещает число 10 в область памяти, на которую указывает переменная а и одновременно задает тип переменной а - целое число. Можно в одной функции присвоить несколько переменных:
(
SETQ a 10 b "213" )
Порядок выполнения нескольких присваиваний в функции SETQ определен слева направо. Если мы напишем:
(
SETQ a 10 b ( + a 10 ) )
то значением переменной b станет 20.
Изменение значения переменной на NIL
освобождает занимаемую ее значением область памяти.
( SETQ a NIL ) сохраняет саму переменную а, но теперь она указывает "в никуда" (для ее значения памяти не выделено).
SETQ - наиболее часто используемая функция присваивания. Она аналогична по своему действия оператору присваивания ":=" в Паскале и в принципе позволяет не задумываться об особенностях организации памяти в Автолиспе.
Вторая функция присваивания - SET
- работает не со значениями, а с самими переменными:
( SET a b ) заставляет переменную а ссылаться на ту же область памяти, что и переменная b.
Как записать в значение переменной атом (число, текстовую строку...) понятно.
А как быть, если в переменную нужно записать список? Например, имеется
список с данными вида: ( 0.25 "АБВ" 46
). Проблема заключается в том, что,
как мы уже знаем, по умолчанию любой список считается программой и первый
же элемент списка, стоящий сразу после открывающей скобки, рассматривается
как имя функции. Если мы напишем функцию присваивания вида:
то интерпретатор попытается вызвать функцию с именем "0.25" и аргументами "АБВ" и "46", что приведет к возникновению ошибки "Неверное имя функции", поскольку функции с именем "0.25" нет и быть не может. Таким образом, необходимо как-то сказать Автолиспу: не пытайся выполнить этот список, это не программа, а данные. Для этого используется функция подавления вычисления списка QUOTE:
Функция QUOTE
запрещает вычисление списка, являющегося ее аргументом и возвращает сам
этот список.
В рассматриваемом примере нужно написать:
(
SETQ a ( QUOTE ( 0.25 "АБВ" 46 ) ) )
и в значением переменной а станет список ( 0.25 "АБВ" 46 ). Поскольку данные в программе встречаются весьма часто, введена сокращенная запись функции QUOTE в виде апострофа:
Применять функцию QUOTE
к атому бессмысленно: ( QUOTE 0.25 )
и 0.25
- одно и то же.
А что будет, если применить функцию QUOTE к переменной? Она вернет саму переменную, а не ее значение:
(
SETQ a 5 )
( SETQ b a ) а значением переменной b будет 5
( SETQ b 'a ) а значением переменной b будет переменная а.
Поэтому функцию SET можно использовать и для изменения значения переменной:
(
SET 'a 10 ) делает то же, что и (
SETQ a 10 )
поскольку запись 'a означает значение переменной а.
Итак, значением одной переменной может быть другая переменная! Такой прием используется редко, но знать о его существовании следует.
Предположим теперь, что мы записали в значение переменной как данные список, который на самом деле является программой:
Как теперь заставить Автолисп вычислить этот список? Для этого есть очень полезная функция EVAL (от evaluation):
Функция EVAL
вычисляет список, являющийся ее аргументом, и возвращает вычисленное значение.
В нашем случае ( EVAL a ) вернет 15. Таким образом, функция EVAL обратна по отношению к функции QUOTE. Ее использование позволяет "на ходу", в ходе выполнения программы, сформировать список-программу (содержащий вызовы функций) и исполнить его. В этом и заключается динамическая модификация текста программы, необходимая для решения задач искусственного интеллекта.
Теперь рассмотрим математические и логические функции Автолиспа, которые для удобства сведены в таблицу 2.1.
Таблица
2.1 - Основные математические функции Лиспа.
|
|
|
|
|
|
a1 a2 ... an | a1+a2+...+an |
|
|
a1 a2 ... an | a1-a2-...-an |
|
|
a1 a2 ... an | a1a2...an |
|
|
a1 a2 ... an | a1/a2/.../an |
|
|
a | a+1 |
|
|
a | a-1 |
|
|
a | ![]() |
|
|
a | ![]() |
|
|
a | ![]() |
|
|
a b | ![]() |
|
|
a b | НОД чисел а, b |
|
|
a | Ln(a) |
|
|
a1 a2 ... an | Минимальное
из чисел
a1 a2 ... an |
|
|
a1 a2 ... an | Максимальное
из чисел
a1 a2 ... an |
|
|
a b | Остаток от деления a/b |
|
|
||
|
|
a | Sin(a), a - в радианах |
|
|
a | Cos(a), a - в радианах |
|
|
a | Atn(a) в радианах |
В языке также предусмотрена встроенная переменная PI, со значением, равным 3.14152...
Пример:
Вычислить площадь треугольника S
со сторонами a, b, c по формуле
Герона:


Запишем программу вычислений:
( SETQ p ( / ( + a b c ) 2 ) )
( SETQ s ( SQRT ( * p ( - p a ) ( - p b )
( - p c ) ) ) )
Для того, чтобы эту программу выполнить, ее можно либо построчно набирать
в ответ на приглашение Автокада "Команда:",
либо записать в текстовый файл с расширением *.LSP
и загрузить его. Функции будут выполнены в процессе загрузки файла.
Внимание!
Автокад не загружает автоматически файл с программой после того, как в
него внесены изменения. Это надо делать принудительно при помощи меню или
функции LOAD.
В противном случае можно долго искать ошибку: программа исправлена, а работает,
как и прежде.
Чтобы просмотреть значение переменной, надо в командной строке набрать
восклицательный знак, а за ним - имя переменной:
выведет на экран значение переменной а.
При наборе программ на Автолиспе легко ошибиться с парностью скобок, поэтому рекомендуется использовать текстовый редактор, отслеживающий скобки (простейший из них - The Norton Editor).
Если неверное по скобкам выражение введено с командной строки Автокада,
то приглашение "Команда:"
меняется на "1>",
где 1 - число незакрытых правых скобок. Следует прервать ввод (нажав Ctrl+Pause
или
Ctrl+Break)
и попробовать еще раз.