Условная операция типа if-then-else (если-то-иначе) осуществляется с помощью функции if:
(if <условие> <выражение1> (<выражение2>] )
Типы аргументов: любые.
Возвращаемое значение: вычисленное значение <выражение1>, если значение <условие> отлично от nil (nil в логических операциях используется как "ложь"); или значение <выражение2>, если значение <условие> равно nil (когда <выражение2> опущено, тогда вместо <выражение2> возвращается nil).
Примеры:
(if (> a b) 1 10) — возвращает 1, если a>b, и 10 — в других случаях;
(if (= h1 h2) (+ h1 15) (* h1 2.5)) — возвращает результат вычисле-ния выражения (+ h1 15), если значения h1 и h2 равны; иначе— результат вычисления выражения (* h1 2.5);
(if (< a b) "a<b") — возвращает строку "а<b" или nil (т.к. <выражение2> опущено);
(if nil "Point") — возвращает nil (т. к. <условие> всегда ложно).
Если функция if используется для выполнения по условию не одного выражения, а нескольких, то эти выражения следует объединить с помощью функции рrоgп (иначе будет синтаксическая ошибка, вызванная неправильным количеством аргументов при обращении к функции if):
(рrоgn <выражение1> <выражение2> ... [<выражениеN>])
Функция объединяет несколько (не менее двух!) выражении в одно, когда по синтаксису языка AutoLISP может использоваться только одно (как в функции if).
Рассмотрим использование функции progn на таком примере. Пусть при выполнении условия (> а b) нужно выполнить выражения (setq с -1), (setq d (-cab)) и (* d b), а при невыполнении условия — выполнить выражения (setq с 2), (setq d (* а Ь) ) И (* d с).
(if (> а b)
(progn
(setq с -1)
(setq d (-cab))
(* d b)
); конец progn
(progn
(setq с 2)
(setq d (* а b))
(* d с)
) ; конец progn
); конец if
Для удобства чтения в этом фрагменте текста программы в начале некоторых строк добавлены пробелы, чтобы открывающая скобка оказалась на одном уровне с закрывающей, а внутренние выражения были смещены относительно ближайших внешних на две позиции вправо. К закрывающим скобкам даны комментарии, согласно правилам их написания.
Условная операция типа case с любым количеством условий осуществляется с помощью функции cond:
(cond (<условие1> [<выражение1> ... ] ) [ (<условие2> [<выражение2> ... ])] ...)
Аргументы: любое количество списков, в каждом из которых на первом месте стоит проверяемое условие, а затем следуют выражения, которые должны быть выполнены (вычислены), если это условие оказалось истинным.
Возвращаемое значение функции cond — последнее вычисленное выражение. Если вычисляемое выражение отсутствует (не задано в списке), то возвращается результат вычисления последнего аргумента <условие>. Если аргументы функции cond не заданы, то возвращается nil.
(cond) — возвращает nil;
(cond (14)) — возвращает 14.
Впрочем, использование функции cond с неполным количеством аргументов не имеет особого смысла.
Рассмотрим задачу: переменной mycolor нужно присвоить текстовое значение с наименованием одного из основных цветов AutoCAD ("красный", "желтый", "зеленый", "голубой", "синий") в зависимости от текущего значения переменной сс, которая принимает значения 1, 2, 3, 4, 5. В случае если значение переменной ее оказалось отличным от перечисленных, то переменной mycolor нужно присвоить "" (пустая строка).
(setq mycolor (cond
((= cc 1) "красный")
((= cc 2) "желтый")
((= cc 3) "зеленый")
((= cc 4) "голубой")
((= cc 5) "синий")
(Т "")
); конец cond
); конец setq
Функция setq присваивает переменной mycolor результат вычисления функции cond. Значение, возвращаемое функцией cond, вычисляется по следующей схеме. Сначала рассматривается список, заданный в качестве первого аргумента— ((= cc 1) "красный") — и проверяется условие, являющееся первым элементом этого списка. Если оказалось, что значение переменной cc равно 1 и, значит, первое условие возвращает "истину", то дальнейшее рассмотрение аргументов функции cond не выполняется, а в качестве возвращаемого значения принимается "красный". Если первое условие не вычислилось как "истина", то проверяется второе условие и т. д. В качестве последнего, шестого, условия стоит т (т. е. "истина" при любых значениях), поэтому, если значение переменной cc не совпало с 1, 2, 3, 4, 5, то в качестве возвращаемого значения функции cond будет принято "" (пустая строка).
Еще один пример иллюстрирует случай, когда по истинности значения <условие> выполняются несколько операторов.
(cond
((= cc 1) (setq abc "красный")
(command "_PLINE" "-50,120.45" "97.66,23.124" "45.7,800" "_С")
) ; = cc 1
((= cc 2) (setq abc "желтый")
(command "_CIRCLE" "-50,120.45" "100")
) ; = cc 2
) ; конец cond
В этом примере функция cond проверяет значение переменной cc. Если оно равно 1, то функция setq присваивает переменной abc значение "красный", а затем AutoCAD рисует замкнутую полилинию с тремя вершинами. Если значение cc равно 2, то функция setq присваивает переменной abc значение "желтый", a AutoCAD рисует окружность радиуса 100. Если окажется, что значение cc не равно ни 1, ни 2, то функция cond вернет nil, не изменяя при этом значения переменной abc и не строя никаких новых примитивов AutoCAD. Поскольку функция command является последним выражением, как в первом, так и во втором условиях функции cond, то во всех трех случаях будет возвращено значение nil (nil является возвращаемым значением функции command — см. разд. 12.3). Однако в данном примере функция cond применена не ради возвращаемого значения, а ради изменения значения переменной abc и построения дополнительной полилинии или окружности.
Существует несколько проверочных функций, которые проверяют конкретные значения или типы:
(minusp <число>) — проверка числа на отрицательность;
(zerop <число>) — проверка числа на ноль;
(numberp <аргумент>) — проверка типа аргумента на число;
(listp <аргумент>) — проверка типа аргумента на список;
(boundp <символ>) — проверка, присвоено ли значение символу AutoLISP; для указания на имя функции его следует предварять апострофом.
Все эти функции возвращают значение т, если аргумент удовлетворяет требуемому условию, и nil — если не удовлетворяет.
(minusp (-52 24 39)) —возвращает т;
(zerop 0.0) — возвращает т;
(numberp -10.0) — возвращает т;
(numberp "1") — возвращает nil;
(listp "1") — возвращает nil;
(listp ' (-21.82)) — возвращает т;
(boundp ' +) — возвращает т.
Функция eq проверяет равенство двух аргументов (аналогична функции =):
(eq <аргумент1> <аргумент2>)
Тип возвращаемого значения: логическое (т, если значения аргументов совпали, и nil, если не совпали).
(eq -10.0 -10) — возвращает т;
(eq о 3) — возвращает nil;
(eq "abc" "АBC") — возвращает nil.
Функция equal проверяет равенство двух объектов (для чисел и списков из числовых величин равенство проверяется в пределах допуска):
(equal <аргумент1> <аргумент2> [<допуск>])
Тип возвращаемого значения: логическое (т, если абсолютная величина разности аргументов не превосходит значение аргумента <допуск>, и nil, если не совпали; если <допуск> не задан, то его значение считается равным нулю). Для аргументов, не являющихся числами или списками из чисел, <допуск> не используется.
(equal -10.0 -10) — возвращает т;
(equal 3.000 3.002 0.002) — возвращает т;
(equal "font" "font") — возвращает т;
(equal ' (1.00 2.13 2.99) ' (1 2.13 3.0) 0.1) — возвращает Т.
8.3.9. Функции организации циклов
Функция while позволяет организовывать операции цикла по многократно проверяемому условию:
(while <условие> <выражение1> [<выражение2> ... [<выражениеN>] ... ] )
Типы аргументов: любые.
Возвращаемое значение функции while: значение <выражением>, когда последнее вычисленное значение аргумента <условие> отлично от nil. При неудачном задании цикл, организуемый с помощью функции while, может оказаться бесконечным.
Рассмотрим следующий пример. Пусть надо вычислить значение n! (факториал), т. е. произведение целых чисел от 1 до n. В данном разделе восклицательный знак используется как знак функции факториала.
(setq i 1 factorial 1)
(while (< i n)
(setq i (1+ i))
(setq factorial (* factorial i))
); конец while
Рассмотрим работу примера, когда число n равно 11 (т. е. вычисляется 11!).
В программе используются переменные i (это переменная, являющаяся счетчиком цикла) и factorial (переменная, которая накапливает произведение чисел, формирующее факториал). Перед входом в цикл они получают начальные значения — соответственно, 1 и 1 (по определению 1! считается равным 1).
Функция while проверяет условие (< i n) для текущего значения i и, если результат вычисления условия отличен от nil, то выполняет внутренние операции (две операции с участием функции setq). Таким образом, при первом входе в цикл i равно 1, проверяемое условие (< 1 n) возвращает значение т ("истина"), и функция while увеличивает i на l (получается i=2) и умножает переменную factorial на i: factorial=l*2 (не что иное как 2!).
Далее снова передается управление на вход в цикл (уже при i=2). Проверка условия опять дает результат "истина", поэтому i получает значение 3 (2+1), a factorial — 6 (2*3). И так далее, пока i не станет равным n (11) и программа покинет цикл, не выполняя внутренних операций. Результат: при n=11 factorial=39, 916,800 (запятые разделяют триады цифр).
Функция repeat используется для организации цикла с фиксированным количеством повторений:
(repeat <количество> [<выражение1> ...] )
Типы аргументов: <количество> — целое число (имеют смысл только положительные числа), <выражение1> — любое выражение. После аргумента <выражение1> могут идти другие выражения, которые нужно выполнить внутри цикла.
Возвращаемое значение — значение последнего вычисленного выражения. Если аргумент <количество> имеет нулевое или отрицательное значение, или после аргумента <количество> не заданы выражения, то функция repeat возвращает nil.
Переработаем предыдущий пример — вместо while воспользуемся функцией repeat.
(setq i 1 factorial 1)
(repeat (1- n)
(setq i (1+ i))
(setq factorial (* factorial i))
); конец repeat
Поскольку входные значения i=1 и factorial = l! =1, то остается умножить factorial на 2, 3, ... , n. Количество таких умножении равно n—1, что на языке AutoLISP записывается как (i- n). Остальное работает как в предыдущем примере.
(if <условие> <выражение1> (<выражение2>] )
Типы аргументов: любые.
Возвращаемое значение: вычисленное значение <выражение1>, если значение <условие> отлично от nil (nil в логических операциях используется как "ложь"); или значение <выражение2>, если значение <условие> равно nil (когда <выражение2> опущено, тогда вместо <выражение2> возвращается nil).
Примеры:
(if (> a b) 1 10) — возвращает 1, если a>b, и 10 — в других случаях;
(if (= h1 h2) (+ h1 15) (* h1 2.5)) — возвращает результат вычисле-ния выражения (+ h1 15), если значения h1 и h2 равны; иначе— результат вычисления выражения (* h1 2.5);
(if (< a b) "a<b") — возвращает строку "а<b" или nil (т.к. <выражение2> опущено);
(if nil "Point") — возвращает nil (т. к. <условие> всегда ложно).
Если функция if используется для выполнения по условию не одного выражения, а нескольких, то эти выражения следует объединить с помощью функции рrоgп (иначе будет синтаксическая ошибка, вызванная неправильным количеством аргументов при обращении к функции if):
(рrоgn <выражение1> <выражение2> ... [<выражениеN>])
Функция объединяет несколько (не менее двух!) выражении в одно, когда по синтаксису языка AutoLISP может использоваться только одно (как в функции if).
Рассмотрим использование функции progn на таком примере. Пусть при выполнении условия (> а b) нужно выполнить выражения (setq с -1), (setq d (-cab)) и (* d b), а при невыполнении условия — выполнить выражения (setq с 2), (setq d (* а Ь) ) И (* d с).
(if (> а b)
(progn
(setq с -1)
(setq d (-cab))
(* d b)
); конец progn
(progn
(setq с 2)
(setq d (* а b))
(* d с)
) ; конец progn
); конец if
Для удобства чтения в этом фрагменте текста программы в начале некоторых строк добавлены пробелы, чтобы открывающая скобка оказалась на одном уровне с закрывающей, а внутренние выражения были смещены относительно ближайших внешних на две позиции вправо. К закрывающим скобкам даны комментарии, согласно правилам их написания.
Условная операция типа case с любым количеством условий осуществляется с помощью функции cond:
(cond (<условие1> [<выражение1> ... ] ) [ (<условие2> [<выражение2> ... ])] ...)
Аргументы: любое количество списков, в каждом из которых на первом месте стоит проверяемое условие, а затем следуют выражения, которые должны быть выполнены (вычислены), если это условие оказалось истинным.
Возвращаемое значение функции cond — последнее вычисленное выражение. Если вычисляемое выражение отсутствует (не задано в списке), то возвращается результат вычисления последнего аргумента <условие>. Если аргументы функции cond не заданы, то возвращается nil.
(cond) — возвращает nil;
(cond (14)) — возвращает 14.
Впрочем, использование функции cond с неполным количеством аргументов не имеет особого смысла.
Рассмотрим задачу: переменной mycolor нужно присвоить текстовое значение с наименованием одного из основных цветов AutoCAD ("красный", "желтый", "зеленый", "голубой", "синий") в зависимости от текущего значения переменной сс, которая принимает значения 1, 2, 3, 4, 5. В случае если значение переменной ее оказалось отличным от перечисленных, то переменной mycolor нужно присвоить "" (пустая строка).
(setq mycolor (cond
((= cc 1) "красный")
((= cc 2) "желтый")
((= cc 3) "зеленый")
((= cc 4) "голубой")
((= cc 5) "синий")
(Т "")
); конец cond
); конец setq
Функция setq присваивает переменной mycolor результат вычисления функции cond. Значение, возвращаемое функцией cond, вычисляется по следующей схеме. Сначала рассматривается список, заданный в качестве первого аргумента— ((= cc 1) "красный") — и проверяется условие, являющееся первым элементом этого списка. Если оказалось, что значение переменной cc равно 1 и, значит, первое условие возвращает "истину", то дальнейшее рассмотрение аргументов функции cond не выполняется, а в качестве возвращаемого значения принимается "красный". Если первое условие не вычислилось как "истина", то проверяется второе условие и т. д. В качестве последнего, шестого, условия стоит т (т. е. "истина" при любых значениях), поэтому, если значение переменной cc не совпало с 1, 2, 3, 4, 5, то в качестве возвращаемого значения функции cond будет принято "" (пустая строка).
Еще один пример иллюстрирует случай, когда по истинности значения <условие> выполняются несколько операторов.
(cond
((= cc 1) (setq abc "красный")
(command "_PLINE" "-50,120.45" "97.66,23.124" "45.7,800" "_С")
) ; = cc 1
((= cc 2) (setq abc "желтый")
(command "_CIRCLE" "-50,120.45" "100")
) ; = cc 2
) ; конец cond
В этом примере функция cond проверяет значение переменной cc. Если оно равно 1, то функция setq присваивает переменной abc значение "красный", а затем AutoCAD рисует замкнутую полилинию с тремя вершинами. Если значение cc равно 2, то функция setq присваивает переменной abc значение "желтый", a AutoCAD рисует окружность радиуса 100. Если окажется, что значение cc не равно ни 1, ни 2, то функция cond вернет nil, не изменяя при этом значения переменной abc и не строя никаких новых примитивов AutoCAD. Поскольку функция command является последним выражением, как в первом, так и во втором условиях функции cond, то во всех трех случаях будет возвращено значение nil (nil является возвращаемым значением функции command — см. разд. 12.3). Однако в данном примере функция cond применена не ради возвращаемого значения, а ради изменения значения переменной abc и построения дополнительной полилинии или окружности.
Существует несколько проверочных функций, которые проверяют конкретные значения или типы:
(minusp <число>) — проверка числа на отрицательность;
(zerop <число>) — проверка числа на ноль;
(numberp <аргумент>) — проверка типа аргумента на число;
(listp <аргумент>) — проверка типа аргумента на список;
(boundp <символ>) — проверка, присвоено ли значение символу AutoLISP; для указания на имя функции его следует предварять апострофом.
Все эти функции возвращают значение т, если аргумент удовлетворяет требуемому условию, и nil — если не удовлетворяет.
(minusp (-52 24 39)) —возвращает т;
(zerop 0.0) — возвращает т;
(numberp -10.0) — возвращает т;
(numberp "1") — возвращает nil;
(listp "1") — возвращает nil;
(listp ' (-21.82)) — возвращает т;
(boundp ' +) — возвращает т.
Функция eq проверяет равенство двух аргументов (аналогична функции =):
(eq <аргумент1> <аргумент2>)
Тип возвращаемого значения: логическое (т, если значения аргументов совпали, и nil, если не совпали).
(eq -10.0 -10) — возвращает т;
(eq о 3) — возвращает nil;
(eq "abc" "АBC") — возвращает nil.
Функция equal проверяет равенство двух объектов (для чисел и списков из числовых величин равенство проверяется в пределах допуска):
(equal <аргумент1> <аргумент2> [<допуск>])
Тип возвращаемого значения: логическое (т, если абсолютная величина разности аргументов не превосходит значение аргумента <допуск>, и nil, если не совпали; если <допуск> не задан, то его значение считается равным нулю). Для аргументов, не являющихся числами или списками из чисел, <допуск> не используется.
(equal -10.0 -10) — возвращает т;
(equal 3.000 3.002 0.002) — возвращает т;
(equal "font" "font") — возвращает т;
(equal ' (1.00 2.13 2.99) ' (1 2.13 3.0) 0.1) — возвращает Т.
8.3.9. Функции организации циклов
Функция while позволяет организовывать операции цикла по многократно проверяемому условию:
(while <условие> <выражение1> [<выражение2> ... [<выражениеN>] ... ] )
Типы аргументов: любые.
Возвращаемое значение функции while: значение <выражением>, когда последнее вычисленное значение аргумента <условие> отлично от nil. При неудачном задании цикл, организуемый с помощью функции while, может оказаться бесконечным.
Рассмотрим следующий пример. Пусть надо вычислить значение n! (факториал), т. е. произведение целых чисел от 1 до n. В данном разделе восклицательный знак используется как знак функции факториала.
(setq i 1 factorial 1)
(while (< i n)
(setq i (1+ i))
(setq factorial (* factorial i))
); конец while
Рассмотрим работу примера, когда число n равно 11 (т. е. вычисляется 11!).
В программе используются переменные i (это переменная, являющаяся счетчиком цикла) и factorial (переменная, которая накапливает произведение чисел, формирующее факториал). Перед входом в цикл они получают начальные значения — соответственно, 1 и 1 (по определению 1! считается равным 1).
Функция while проверяет условие (< i n) для текущего значения i и, если результат вычисления условия отличен от nil, то выполняет внутренние операции (две операции с участием функции setq). Таким образом, при первом входе в цикл i равно 1, проверяемое условие (< 1 n) возвращает значение т ("истина"), и функция while увеличивает i на l (получается i=2) и умножает переменную factorial на i: factorial=l*2 (не что иное как 2!).
Далее снова передается управление на вход в цикл (уже при i=2). Проверка условия опять дает результат "истина", поэтому i получает значение 3 (2+1), a factorial — 6 (2*3). И так далее, пока i не станет равным n (11) и программа покинет цикл, не выполняя внутренних операций. Результат: при n=11 factorial=39, 916,800 (запятые разделяют триады цифр).
Функция repeat используется для организации цикла с фиксированным количеством повторений:
(repeat <количество> [<выражение1> ...] )
Типы аргументов: <количество> — целое число (имеют смысл только положительные числа), <выражение1> — любое выражение. После аргумента <выражение1> могут идти другие выражения, которые нужно выполнить внутри цикла.
Возвращаемое значение — значение последнего вычисленного выражения. Если аргумент <количество> имеет нулевое или отрицательное значение, или после аргумента <количество> не заданы выражения, то функция repeat возвращает nil.
Переработаем предыдущий пример — вместо while воспользуемся функцией repeat.
(setq i 1 factorial 1)
(repeat (1- n)
(setq i (1+ i))
(setq factorial (* factorial i))
); конец repeat
Поскольку входные значения i=1 и factorial = l! =1, то остается умножить factorial на 2, 3, ... , n. Количество таких умножении равно n—1, что на языке AutoLISP записывается как (i- n). Остальное работает как в предыдущем примере.